2015-01-30 3 views
1

Я пытаюсь понять Духа, а это значит, что я ноб у него (отсюда и ожидать отсутствия правильной терминологии внизу).Boost Spirit: что-то вроде перестановки, но не точно

Я должен разобрать это:

value1 = 10 
value2 = 20 
value3 = 30 
value4 = 40 

Порядок не имеет значения, но каждый «value1» ... линия «value4» должен присутствовать ровно один раз. Это было бы хорошо:

value1 = 10 
value4 = 40 
value2 = 20 
value3 = 30 

, но это не будет хорошо (дублируется "value1"):

value1 = 10 
value2 = 20 
value3 = 30 
value4 = 40 
value1 = 10000 

Также это (отсутствует "value4"):

value1 = 10 
value2 = 20 
value3 = 30 

Как мог Я достигаю этого с Духом?

Бонус вопрос: что, если строка «значение3» является необязательной?

MaX.

ответ

1

Я бы использовал синтаксический анализатор + добавленную проверку действительности.

Таким образом, вам не нужно писать все, и вы все равно можете достичь требуемых ограничений.

Live On Coliru

#include <boost/fusion/adapted/struct.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/optional/optional_io.hpp> 

struct X { 
    boost::optional<int> value1; 
    boost::optional<int> value2; 
    boost::optional<int> value3; 
    boost::optional<int> value4; 
}; 

static bool is_valid(X const& x) { return x.value1 && x.value2 && x.value4; } // value3 is optional 

BOOST_FUSION_ADAPT_STRUCT(X, 
     (boost::optional<int>, value1) 
     (boost::optional<int>, value2) 
     (boost::optional<int>, value3) 
     (boost::optional<int>, value4) 
    ) 

int main() { 
    namespace qi = boost::spirit::qi; 
    namespace phx = boost::phoenix; 
    using It = std::string::const_iterator; 

    qi::rule<It, X(), qi::space_type> grammar; 
    grammar = 
     (("value1" > qi::lit('=') > qi::int_)^
     ("value2" > qi::lit('=') > qi::int_)^
     ("value3" > qi::lit('=') > qi::int_)^
     ("value4" > qi::lit('=') > qi::int_)) 
     >> qi::eoi 
     >> qi::eps(phx::bind(is_valid, qi::_val)) 
     ; 

    for (std::string const& input : { 
      "value1 = 10\nvalue2 = 20\nvalue3 = 30\nvalue4 = 40\n", 
      // Order doesn't matter but each value1 ... value4 line must be present exactly once. This would be OK: 
      "value1 = 10\nvalue4 = 40\nvalue2 = 20\nvalue3 = 30\n", 
      // But this would not be OK (duplicated value1): 
      "value1 = 10\nvalue2 = 20\nvalue3 = 30\nvalue4 = 40\nvalue1 = 10000\n", 
      // Nor this (missing value4): 
      "value1 = 10\nvalue2 = 20\nvalue3 = 30\n", 
      // value3 _is_ optional though: 
      "value1 = 10\nvalue2 = 20\nvalue4 = 40\n", 
     }) 
    { 
     std::cout << "---------------------------------------------------------\n"; 
     std::cout << "Parsing '" << input << "'\n"; 
     auto f(input.begin()), l(input.end()); 
     X parsed; 
     bool ok = phrase_parse(f, l, grammar, qi::space, parsed); 

     if (ok) { 
      std::cout << "Parsing succeeded: " << boost::fusion::as_vector(parsed) << "\n"; 
     } else { 
      std::cout << "Parsing failed\n"; 
     } 

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

Печать

--------------------------------------------------------- 
Parsing 'value1 = 10 
value2 = 20 
value3 = 30 
value4 = 40 
' 
Parsing succeeded: (10 20 30 40) 
--------------------------------------------------------- 
Parsing 'value1 = 10 
value4 = 40 
value2 = 20 
value3 = 30 
' 
Parsing succeeded: (10 20 30 40) 
--------------------------------------------------------- 
Parsing 'value1 = 10 
value2 = 20 
value3 = 30 
value4 = 40 
value1 = 10000 
' 
Parsing failed 
Remaing input 'value1 = 10 
value2 = 20 
value3 = 30 
value4 = 40 
value1 = 10000 
' 
--------------------------------------------------------- 
Parsing 'value1 = 10 
value2 = 20 
value3 = 30 
' 
Parsing failed 
Remaing input 'value1 = 10 
value2 = 20 
value3 = 30 
' 
--------------------------------------------------------- 
Parsing 'value1 = 10 
value2 = 20 
value4 = 40 
' 
Parsing succeeded: (10 20 -- 40) 

Как вы можете видеть, последний обращается бонусный вопрос.

Посмотрите на директиве ключевого слова парсера из Хранилища Духа тоже:

Это позволяет установить мин/макс вхождения

+0

Благодаря sehe, директива по ключевым словам, похоже, соответствует законопроекту. Однако в вашем решении любой элемент может быть необязательным, в то время как я был более заинтересован в том, чтобы один из них был необязательным. Я прав ? – HornetMaX

+0

@HometMaX Вы пробовали? Я думаю, что я точно сказал, почему я буду делать это так :) В любом случае вы можете использовать парсер ключевых слов (у меня нет большого опыта с этим, я просто знаю, что он существует. Это не часть поддерживаемого Qi) – sehe

+0

Привет, нет, я еще не пробовал. Я бы хотел быть на 100% уверен, что понимаю это, прежде чем записывать его (потому что реальный файл, который я должен разобрать, более сложный, чем пример выше). Я также немного напуган использованием Fusion и Phoenix (что я вообще не знаю): все еще размышляю, стоит ли их изучать, или я могу это сделать без. Не уверен, что я получаю то, что «не расстается» поддерживаемых интерфейсов Qi ". Спасибо за помощь ! – HornetMaX