提升精神太贪心了

时间:2011-03-18 17:31:35

标签: c++ 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;
}

1 个答案:

答案 0 :(得分: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的非空前缀,您的代码也会报告匹配。

更新:添加了后缀打印。