2012-04-24 106 views
5

我想解析一些句子,其中一些字符串可能不加引號,引用引號或引用引號。下面的代碼幾乎可以工作 - 但它不能匹配收盤報價。我猜這是因爲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

回答

12

對於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