8

我在对 boost::spirit 的深深钦佩和不理解它的永恒沮丧之间徘徊;)

我对过于贪婪的字符串有问题,因此它不匹配。下面是一个由于 txt 规则耗尽而无法解析的最小示例。

关于我想做的更多信息:目标是解析一些伪 SQL,我跳过空格。在类似的声明中

select foo.id, bar.id from foo, baz 

我需要将from其视为特殊关键字。规则类似于

"select" >> txt % ',' >> "from" >> txt % ',' 

但它显然不起作用,因为它被 bar.id from foo视为一个项目。

#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
int main(int, char**) {
    auto txt = +(qi::char_("a-zA-Z_"));
    auto rule = qi::lit("Hello") >> txt % ',' >> "end";
    std::string str = "HelloFoo,Moo,Bazend";
    std::string::iterator begin = str.begin();
    if (qi::parse(begin, str.end(), rule))
        std::cout << "Match !" << std::endl;
    else
        std::cout << "No match :'(" << std::endl;
}
4

1 回答 1

10

这是我的版本,标记了更改:

#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
int main(int, char**) {
  auto txt = qi::lexeme[+(qi::char_("a-zA-Z_"))];     // CHANGE: avoid eating spaces
  auto rule = qi::lit("Hello") >> txt % ',' >> "end";
  std::string str = "Hello Foo, Moo, Baz end";        // CHANGE: re-introduce spaces
  std::string::iterator begin = str.begin();
  if (qi::phrase_parse(begin, str.end(), rule, qi::ascii::space)) {          // CHANGE: used phrase_parser with a skipper
    std::cout << "Match !" << std::endl << "Remainder (should be empty): '"; // CHANGE: show if we parsed the whole string and not just a prefix
    std::copy(begin, str.end(), std::ostream_iterator<char>(std::cout));
    std::cout << "'" << std::endl;
  }
  else {
    std::cout << "No match :'(" << std::endl;
  }
}

这使用 GCC 4.4.3 和 Boost 1.4something 编译和运行;输出:

Match !
Remainder (should be empty): ''

通过使用lexeme,您可以有条件地避免使用空格,以便txt仅匹配单词边界。这产生了预期的结果:因为"Baz"后面没有逗号,并且txt不吃空格,所以我们永远不会意外使用"end".

无论如何,我不能 100% 确定这就是您要查找的内容 - 特别是str缺少空格作为说明性示例,或者您是否以某种方式被迫使用这种(无空格)格式?

旁注:如果要确保已解析整个字符串,请添加检查以查看begin == str.end(). 如前所述,即使仅str解析了非空前缀 of,您的代码也会报告匹配项。

更新:添加了后缀打印。

于 2011-03-18T18:01:31.827 回答