2017-04-12 8 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>は偽/空ではありません。むしろ、それは価値のコピーを持っています。ペアの2番目の部分にも値があります。

タグなしのキーワードをタグ(構文規則など、小数点など)にすることはできません。

私は間違っていますか?これはPEGと概念的に間違っていますか?

答えて

2

代わりに、値のコピーがあります。ペアの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' 
関連する問題