2017-04-12 5 views
3

공백으로 구분되고 선택적으로 태그가 지정된 키워드 문자열을 구문 분석하려고합니다. 예Boost.Spirit 구문 분석 선택적 접두사

결장 전 식 태그이며,이 선택적
descr:expense type:receivable customer 27.3 

경우 (즉, 기본 태그가 가정된다).

필자는 파서가 내가 원하는 것을 할 수 없다. 나는 canonical example에서 몇 가지 사소한 수정을했다. 그 목적은 키/값 쌍 (HTTP 쿼리 문자열과 비슷 함)을 구문 분석하는 것이다. 태그가 밖으로 남아 나는 그것을 구문 분석 그러나

typedef std::pair<boost::optional<std::string>, std::string> pair_type; 
typedef std::vector<pair_type> pairs_type; 

template <typename Iterator> 
struct field_value_sequence_default_field 
    : qi::grammar<Iterator, pairs_type()> 
{ 
    field_value_sequence_default_field() 
     : field_value_sequence_default_field::base_type(query) 
    { 
     query = pair >> *(qi::lit(' ') >> pair); 
     pair = -(field >> ':') >> value; 
     field = +qi::char_("a-zA-Z0-9"); 
     value = +qi::char_("a-zA-Z0-9+-\\."); 
    } 

    qi::rule<Iterator, pairs_type()> query; 
    qi::rule<Iterator, pair_type()> pair; 
    qi::rule<Iterator, std::string()> field, value; 
}; 

,의 optional<string> 거짓/비어 있지 않습니다. 오히려 가치의 사본을 얻습니다. 쌍의 두 번째 부분에도 값이 있습니다.

태그없는 키워드가 태그 (구문 규칙, 예 : 소수점 포함)가 될 수 없다면 예상대로 작동합니다.

내가 뭘 잘못하고 있니? 이것은 PEG와의 개념적인 실수인가?

답변

2

대신 값의 사본이 있습니다. 쌍의 두 번째 부분에도 값이 있습니다.

이것은 컨테이너 속성 및 백 트랙킹의 일반적인 함정입니다. qi::hold을 사용하십시오. Understanding Boost.spirit's string parser

pair = -qi::hold[field >> ':'] >> value; 

전체 샘플 Live On Coliru

#include <boost/spirit/include/qi.hpp> 
#include <boost/fusion/adapted/std_pair.hpp> 
#include <boost/optional/optional_io.hpp> 
#include <iostream> 

namespace qi = boost::spirit::qi; 

typedef std::pair<boost::optional<std::string>, std::string> pair_type; 
typedef std::vector<pair_type> pairs_type; 

template <typename Iterator> 
struct Grammar : qi::grammar<Iterator, pairs_type()> 
{ 
    Grammar() : Grammar::base_type(query) { 
     query = pair % ' '; 
     pair = -qi::hold[field >> ':'] >> value; 
     field = +qi::char_("a-zA-Z0-9"); 
     value = +qi::char_("a-zA-Z0-9+-\\."); 
    } 
    private: 
    qi::rule<Iterator, pairs_type()> query; 
    qi::rule<Iterator, pair_type()> pair; 
    qi::rule<Iterator, std::string()> field, value; 
}; 

int main() 
{ 
    using It = std::string::const_iterator; 

    for (std::string const input : { 
      "descr:expense type:receivable customer 27.3", 
      "expense type:receivable customer 27.3", 
      "descr:expense receivable customer 27.3", 
      "expense receivable customer 27.3", 
    }) { 
     It f = input.begin(), l = input.end(); 

     std::cout << "==== '" << input << "' =============\n"; 
     pairs_type data; 
     if (qi::parse(f, l, Grammar<It>(), data)) { 
      std::cout << "Parsed: \n"; 
      for (auto& p : data) { 
       std::cout << p.first << "\t->'" << p.second << "'\n"; 
      } 
     } else { 
      std::cout << "Parse failed\n"; 
     } 

     if (f != l) 
      std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n"; 
    } 
} 

인쇄

==== 'descr:expense type:receivable customer 27.3' ============= 
Parsed: 
descr ->'expense' 
type ->'receivable' 
-- ->'customer' 
-- ->'27.3' 
==== 'expense type:receivable customer 27.3' ============= 
Parsed: 
-- ->'expense' 
type ->'receivable' 
-- ->'customer' 
-- ->'27.3' 
==== 'descr:expense receivable customer 27.3' ============= 
Parsed: 
descr ->'expense' 
-- ->'receivable' 
-- ->'customer' 
-- ->'27.3' 
==== 'expense receivable customer 27.3' ============= 
Parsed: 
-- ->'expense' 
-- ->'receivable' 
-- ->'customer' 
-- ->'27.3'