用boost :: spirit解析带引号的字符串

问题描述:

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

要完全清楚:未加引号的字符串解析。像'hello'这样的引用字符串将解析开放报价',所有字符hello,但后来未能解析最终报价'

我做了另一次尝试,类似boost tutorials中的开始/结束标记匹配,但没有成功。

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上述示例)经解决方案是首选,但是从实用的角度来看,我会用任何作品!

+0

对于记录,使得'炭qq'的'的成员变量结构test_parser'中完全相同的方式失败。 – Zero 2012-04-24 00:11:31

+0

以“同样的方式”失败你没有告诉我们这个失败了(尽管我能想象它是由于'qq'参考)。 – 2012-04-24 00:16:29

+0

@NicolBolas这是代码中的一条评论 - 我已经澄清了这个问题,谢谢指出。我也怀疑ref(qq),但boost lambda&co的缺点是它们很难调试,因为你无法在传统意义上逐步完成! – Zero 2012-04-24 00:30:50

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

qi::locals是保持表达式解析器内部本地状态规范方式。您的其他选择是延长qq的生命周期(例如,通过使其成为语法课程的成员)。最后,您也可能对inherited attributes感兴趣。这种机制为您提供了一种通过“参数”(传递本地状态)来调用规则/语法的方法。

注意有与使用克林运营商+的注意事项:这是贪婪的,如果串不与预期报价终止解析失败。

见另一个答案我写了治疗任意内容更完整的例子(可选/部分)引用的字符串,允许带引号的字符串内的报价和更多的事情的逃避这样的:

我已经减少了语法的相关位,并包含了几个测试案例:

#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: ' 
+0

谢谢,这正是我之后的事情。 您能否发布任何有关当地人的文档/例子的链接,我花了一段时间才注意到规则签名中的'qi :: local ',这对我和任何人都是一个很好的参考否则看着这个问题。 – Zero 2012-04-26 03:25:52

+0

@零感谢!而且,erm ** ['qi :: locals'](http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/parser_concepts/nonterminal.html# spirit.qi.reference.parser_concepts.nonterminal.locals)**在我的答案中是一个超链接:) - _click它的文档_ – sehe 2012-04-26 06:33:42

+0

@零对于一个很好的示例,我会引用您链接到您的问题的页面,值得注意的这里:[再次采取](http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/tutorials/mini_xml___asts_.html#spirit.qi.tutorials.mini_xml___asts_。 one_more_take) – sehe 2012-04-26 06:36:33