用boost :: spiritparsing引用的string

我想parsing一个句子,其中一些string可能不加引号,“引用”或“引用”。 下面的代码几乎可以工作 – 但它不能匹配收盘报价。 我猜这是因为qq的参考。 在代码中对修改进行了注释,“引用”或“引用”中的修改重新parsing也有助于显示原始问题与结束引用。 代码还描述了确切的语法。

要完全清楚:未加引号的stringparsing。 像'hello'这样'hello'引用string将parsing开放引用' ,所有字符hello ,但是不能parsing最后的引用'

我又做了一个尝试,类似于boost教程中的开始/结束标记匹配,但没有成功。

 template <typename Iterator> struct test_parser : qi::grammar<Iterator, dectest::Test(), ascii::space_type> { test_parser() : test_parser::base_type(test, "test") { using qi::fail; using qi::on_error; using qi::lit; using qi::lexeme; using ascii::char_; using qi::repeat; using namespace qi::labels; using boost::phoenix::construct; using boost::phoenix::at_c; using boost::phoenix::push_back; using boost::phoenix::val; using boost::phoenix::ref; using qi::space; char qq; arrow = lit("->"); open_quote = (char_('\'') | char_('"')) [ref(qq) = _1]; // Remember what the opening quote was close_quote = lit(val(qq)); // Close must match the open // close_quote = (char_('\'') | char_('"')); // Enable this line to get code 'almost' working quoted_string = open_quote >> +ascii::alnum >> close_quote; unquoted_string %= +ascii::alnum; any_string %= (quoted_string | unquoted_string); test = unquoted_string [at_c<0>(_val) = _1] > unquoted_string [at_c<1>(_val) = _1] > repeat(1,3)[any_string] [at_c<2>(_val) = _1] > arrow > any_string [at_c<3>(_val) = _1] ; // .. <snip>set rule names on_error<fail>(/* <snip> */); // debug rules } qi::rule<Iterator> arrow; qi::rule<Iterator> open_quote; qi::rule<Iterator> close_quote; qi::rule<Iterator, std::string()> quoted_string; qi::rule<Iterator, std::string()> unquoted_string; qi::rule<Iterator, std::string()> any_string; // A quoted or unquoted string qi::rule<Iterator, dectest::Test(), ascii::space_type> test; }; // main() // This example should fail at the very end // (ie not parse "str3' because of the mismatched quote // However, it fails to parse the closing quote of str1 typedef boost::tuple<string, string, vector<string>, string> DataT; DataT data; std::string str("addx001 add 'str1' \"str2\" -> \"str3'"); std::string::const_iterator iter = str.begin(); const std::string::const_iterator end = str.end(); bool r = phrase_parse(iter, end, grammar, boost::spirit::ascii::space, data); 

对于奖金信用:避免本地数据成员(如上例中的char qq )的解决scheme将是首选,但从实际的angular度来看,我将使用任何可行的方法!

在离开构造函数之后,对qq的引用变成悬而未决,所以这确实是一个问题。

qi::locals是在parsing器expression式中保持本地状态的规范方法。 你的另一个select是延长qq的生命周期(通过使它成为语法类的成员,例如)。 最后,你也可能对inherited attributes感兴趣。 这个机制给你一个方法来调用一个规则/语法与'参数'(传递本地状态)。

注意:使用kleene运算符+有一些注意事项:它是贪婪的,如果string没有以期望的引用结束,则parsing失败。

请参阅我写的另一个答案,以处理(可选/部分)引用的string中的任意内容的更完整的例子,它允许转义引号内的引号和更多的东西,如:

  • 如何使我的拆分工作只能在一个实际的行,并能够跳过string的引用部分?

我已经将语法减less到了相关位,并且包含了一些testing用例:

 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/fusion/adapted.hpp> namespace qi = boost::spirit::qi; template <typename Iterator> struct test_parser : qi::grammar<Iterator, std::string(), qi::space_type, qi::locals<char> > { test_parser() : test_parser::base_type(any_string, "test") { using namespace qi; quoted_string = omit [ char_("'\"") [_a =_1] ] >> no_skip [ *(char_ - char_(_a)) ] >> lit(_a) ; any_string = quoted_string | +qi::alnum; } qi::rule<Iterator, std::string(), qi::space_type, qi::locals<char> > quoted_string, any_string; }; int main() { test_parser<std::string::const_iterator> grammar; const char* strs[] = { "\"str1\"", "'str2'", "'str3' trailing ok", "'st\"r4' embedded also ok", "str5", "str6'", NULL }; for (const char** it = strs; *it; ++it) { const std::string str(*it); std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); std::string data; bool r = phrase_parse(iter, end, grammar, qi::space, data); if (r) std::cout << "Parsed: " << str << " --> " << data << "\n"; if (iter!=end) std::cout << "Remaining: " << std::string(iter,end) << "\n"; } } 

输出:

 Parsed: "str1" --> str1 Parsed: 'str2' --> str2 Parsed: 'str3' trailing ok --> str3 Remaining: trailing ok Parsed: 'st"r4' embedded also ok --> st"r4 Remaining: embedded also ok Parsed: str5 --> str5 Parsed: str6' --> str6 Remaining: '