Search code examples
c++parsingboostboost-spiritboost-spirit-qi

How to use boost::spirit to parse a sequence of words into a vector?


I'm trying to learn boost::spirit. As an example, I'm trying to parse a sequence of words into a vector<string>. I tried this:

#include <boost/spirit/include/qi.hpp>
#include <boost/foreach.hpp>

namespace qi = boost::spirit::qi;

int main() {

  std::vector<std::string> words;
  std::string input = "this is a test";

  bool result = qi::phrase_parse(
      input.begin(), input.end(),
      +(+qi::char_),
      qi::space,
      words);

  BOOST_FOREACH(std::string str, words) {
    std::cout << "'" << str << "'" << std::endl;
  }
}

which gives me this output:

'thisisatest'

but I wanted the following output, where each word is matched separately:

'this'
'is'
'a'
'test'

If possible, I'd like to avoid having to define my own qi::grammar subclass for this simple case.


Solution

  • You're fundamentally misunderstanding the purpose of (or at least misusing) a skip parser – qi::space, used as a skip parser, is for making your parser whitespace agnostic such that there is no difference between a b and ab.

    In your case, the whitespace is important, as you want it to delimit words. Consequently, you shouldn't be skipping whitespace, and you want to use qi::parse rather than qi::phrase_parse:

    #include <vector>
    #include <string>
    #include <iostream>
    #include <boost/foreach.hpp>
    #include <boost/spirit/include/qi.hpp>
    
    int main()
    {
        namespace qi = boost::spirit::qi;
    
        std::string const input = "this is a test";
    
        std::vector<std::string> words;
        bool const result = qi::parse(
            input.begin(), input.end(),
            +qi::alnum % +qi::space,
            words
        );
    
        BOOST_FOREACH(std::string const& str, words)
        {
            std::cout << '\'' << str << "'\n";
        }
    }
    

    (Now updated with G. Civardi's fix.)