Соответствие грамматики Boost spirit шумному вводу

#c #boost #boost-spirit #boost-spirit-qi

#c #повышение #boost-spirit #повышение-духа-ци #boost-spirit-qi

Вопрос:

Я пытаюсь проанализировать шумный ввод, в идеале я мог бы увидеть, соответствует ли строка правилу, и если она действительно получает нужные мне данные, а остальные отбрасывает.

Данные, которые я хочу, следующие.

 Event: Newstate
Channel: SIP/104-000001bb
ChannelState: 6
ChannelStateDesc: Up
  

Я хочу убедиться, что это событие имеет тип new state.

И мне нужно состояние канала. Остальное меня не волнует (пока), поэтому я хочу игнорировать это, я хочу, чтобы оно было гибким и принимало любую старую чушь между важными вещами, на самом деле я не хочу сказать, игнорируйте эту строку, а скорее игнорируйте что-либо между событием и состоянием конца канала, где я фиксирую значение.

Пока у меня есть:

 typedef boost::fusion::vector2<std::string, std::string> vect;
qi::rule<std::string::iterator, vect(), space> rule_ =
            lit("Event: ")      >> *char_("a-zA-Z") >>  
            qi::omit[ *char_ ]  >>  
            "ChannelState: "    >> *char_("0-9")    >>  
            qi::omit[ *char_ ];
  

но по какой-то причине это не работает, я всегда получаю false, когда делаю это:

 vect v;
bool r=qi::parse(it, str.end(), rule_, v); 
  

РЕДАКТИРОВАТЬ: компилятор Boost версии 1.42 g 4.4 Spirit 0x2020

Ответ №1:

Помните: анализатор Spirit является жадным. Это означает, что если вы это сделаете qi::omit[ <something> ] , он будет продолжать пропускать символы до тех пор, пока <something> больше не будет выполнено. Поскольку <something> это буквально что угодно ( char_ соответствует любому символу, поэтому *char_ соответствует всем символам), он съест всю оставшуюся часть строки. Тогда это вызовет ошибку, потому что она так и не дошла до «ChannelState: «.

Ваш способ сделать это просто не будет работать. У вас должен быть какой-то выключатель, чтобы остановить *char_ от поглощения всего.

Я не понимаю, почему вы просто не разбираете их все в std::map , вместо того, чтобы делать это по частям. Затем вы можете просто выбрать нужные элементы. Вы говорите, что вам пока не нужны некоторые элементы, поэтому просто игнорируйте их.

Это будет сделано следующим образом:

 //Includes
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_pair.hpp>

//Code
using namespace boost::spirit;
using ascii::char_;
using ascii::string;

qi::rule<std::string::iterator, std::pair<std::string, std::string>() > pair_rule =
  *(char_ - ':') >> ':' >>
  qi::omit[*ascii::space] >>
  *(char_ - eol) >> (eol || eoi);

qi::rule<std::string::iterator, std::map<std::string, std::string>() > map_rule =
   pair_rule;

std::map<std::string, std::string> v;
bool r = qi::parse(test.begin(), test.end(), map_rule, v); 
  

Обратите внимание, что это работает на Boost 1.47. Я подозреваю, что в более ранних версиях это не сработает.

Компилятор Boost версии 1.42 g 4.4 Spirit 0x2020

Они довольно старые. Вам следует подумать об обновлении. Теперь повышение до 1.47.

Комментарии:

1. Спасибо за ответ, мне нужно будет разобраться с этим, когда я вернусь к работе завтра. Я знаю, что эти версии старые, но я должен убедиться, что они скомпилированы на текущей версии debian (squeeze), которая навсегда осталась в прошлом:(

2. @111111: Даже если элементы std::pair и std::map не работают в более старых версиях, вы всегда можете изменить атрибут для хранения std::vector структуры, содержащей два std::string элемента.

3. Да, у меня все равно возникло желание сделать это, поскольку в большинстве случаев было бы не более 15 элементов, я бы подумал, что накладные расходы на std ::map были бы расточительными.