2012-04-24 18 views
5

मैं एक वाक्य को पार करना चाहता हूं जहां कुछ तारों को 'उद्धृत' या "उद्धृत" किया जा सकता है। नीचे दिया गया कोड लगभग काम करता है - लेकिन यह बंद उद्धरण मिलान करने में विफल रहता है। मुझे अनुमान है कि यह qq संदर्भ की वजह से है। कोड में एक संशोधन की टिप्पणी की जाती है, संशोधित "उद्धृत" या 'उद्धृत "में संशोधन का परिणाम भी विश्लेषण करता है और मूल समस्या को समापन उद्धरण के साथ दिखाने में मदद करता है। कोड सटीक व्याकरण का भी वर्णन करता है।पार्स को बढ़ावा देने के साथ स्ट्रिंग उद्धृत :: भावना

पूरी तरह स्पष्ट होने के लिए: अनगिनत स्ट्रिंग पार्स। '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

रिकॉर्ड के लिए, 'बनाने चार' के एक सदस्य चर struct test_parser' बिल्कुल उसी तरह विफल रहता है qq'। – Zero

+0

क्या "वैसे ही" में विफल रहता है? आपने हमें यह नहीं बताया है कि यह कैसे विफल रहता है (हालांकि मैं छवि कर सकता हूं यह 'qq' संदर्भ के कारण है)। –

+0

@ निकोलबोलस यह कोड में एक टिप्पणी थी - मैंने तब से प्रश्न स्पष्ट किया है, इंगित करने के लिए धन्यवाद।मुझे रेफरी (क्यूक) पर भी संदेह है, लेकिन बूंद लैम्ब्डा और सह का नकारात्मक पक्ष यह है कि वे डीबग करने के लिए मुश्किल हैं क्योंकि आप पारंपरिक अर्थ में कदम नहीं उठा सकते हैं! – Zero

उत्तर

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 :: स्थानीय ' नोटिस करने में कुछ समय लगा, और यह मेरे और किसी के लिए एक अच्छा संदर्भ होगा और इस सवाल को देख रहे हैं। – Zero

+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) ** मेरे उत्तर में एक हाइपरलिंक था :) - _ इसे दस्तावेज_ – sehe

+0

@Zero के लिए एक अच्छा नमूना के लिए क्लिक करें, मैं उस पृष्ठ का उल्लेख करता हूं जिसे आपने अपने प्रश्न में लिंक किया था, विशेष रूप से यहां: [वन मोर टेक] (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

संबंधित मुद्दे