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

≡放荡痞女 提交于 2020-01-23 05:51:55

问题


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.


回答1:


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.)




回答2:


I believe this is the minimal version. qi::omit applied on the qi list parser separator is not necessary - it does not generate any output attribute(s). For details see: http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/operator/list.html

#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";
  }
}



回答3:


Just in case someone else run into my problem of leading spaces.

I had been using ildjarn's solution, until I ran into a string that starts with some spaces.

std::string const input = " this is a test";

It took me a while to figure out that the leading space leads to a failure of function qi::parse(...). The solution is to trim the input leading spaces before calling qi::parse().



来源:https://stackoverflow.com/questions/10421841/how-to-use-boostspirit-to-parse-a-sequence-of-words-into-a-vector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!