Разбор строки (с пробелами), но игнорирование пробелов в конце (Spirit) - PullRequest
1 голос
/ 31 января 2012

У меня есть входная строка, которую я пытаюсь проанализировать. Это может выглядеть так:

sys(error1, 2.3%)
sys(error2 , 2.4%)
sys(this error , 3%)

Обратите внимание на пробел иногда перед запятой. В моем грамматике (библиотека «Spirit Spirit») я бы хотел записать «error1», «error2» и «this error» соответственно.

Вот оригинальная грамматика, которую я должен был запечатлеть - которая поглощала место в конце имени:

name_string %= lexeme[+(char_ - ',' - '"')];
name_string.name("Systematic Error Name");

start = (lit("sys")|lit("usys")) > '('
  > name_string[boost::phoenix::bind(&ErrorValue::SetName, _val, _1)] > ','
  > errParser[boost::phoenix::bind(&ErrorValue::CopyErrorAndRelative, _val, _1)]
  > ')';

Моя попытка исправить это была первой:

name_string %= lexeme[*(char_ - ',' - '"') > (char_ - ',' - '"' - ' ')];

однако это полностью провалилось. Похоже, не удается разобрать что-либо с пробелом посередине.

Я довольно новичок в Духе - так что, возможно, я упускаю что-то простое. Похоже, лексема отключается, пропуская на переднем крае - мне нужно что-то, что делает это на переднем и заднем фронте.

Заранее спасибо за любую помощь!

Благодаря псур ниже, я смог собрать ответ. Он не идеален (см. Ниже), но я подумал, что обновлю пост, чтобы все могли видеть его в контексте и красиво отформатировать:

qi::rule<Iterator, std::string(), ascii::space_type> name_word;
qi::rule<Iterator, std::string(), ascii::space_type> name_string;
ErrorValueParser<Iterator> errParser;

name_word %= +(qi::char_("_a-zA-Z0-9+"));
//name_string %= lexeme[name_word >> *(qi::hold[+(qi::char_(' ')) >> name_word])];

name_string %= lexeme[+(qi::char_("-_a-zA-Z0-9+")) >> *(qi::hold[+(qi::char_(' ')) >> +(qi::char_("-_a-zA-Z0-9+"))])];

start = (
         lit("sys")[bind(&ErrorValue::MakeCorrelated, _val)]
         |lit("usys")[bind(&ErrorValue::MakeUncorrelated, _val)]
         )
  >> '('
  >> name_string[bind(&ErrorValue::SetName, _val, _1)] >> *qi::lit(' ')
  >> ','
  >> errParser[bind(&ErrorValue::CopyErrorAndRelative, _val, _1)]
  >> ')';

Это работает! Ключом к этому является name_string, а в нем - оператор qi :: hold, с которым я до этого не был знаком. Это почти как подправило: все, что находится внутри qi :: hold [...], должно успешно проанализировать, чтобы оно пошло. Таким образом, выше, это позволит только пробел после слова, если есть другое слово после. В результате, если последовательность слов заканчивается пробелом, эти последние пробелы не будут проанализированы! Они могут быть поглощены следующим * qi :: lit ('') (см. Правило запуска).

Есть две вещи, которые я хотел бы выяснить, как улучшить здесь:

  • Было бы неплохо поместить фактический разбор строки в name_word. Проблема заключается в объявлении name_word - оно терпит неудачу, когда оно помещается в соответствующее место в определении name_string.

  • Было бы еще лучше, если бы name_string мог включать разбор завершающих пробелов, хотя его возвращаемое значение не учитывалось. Я думаю, я знаю, как это сделать ...

Когда / если я это выясню, я обновлю этот пост. Спасибо за помощь!

1 Ответ

2 голосов
/ 10 февраля 2012

Для вас должны работать следующие правила:

name_word %= +(qi::char_("_a-zA-Z0-9"));

start %= qi::lit("sys(")
  >> qi::lexeme[ name_word >> *(qi::hold[ +(qi::char_(' ')) >> name_word ]) ]
  >> *qi::lit(' ')
  >> qi::lit(',')
  // ...

name_word разбирать только одно слово в имени;Я предположил, что он содержит только буквы, цифры и подчеркивание.

В start правило qi::hold важно.Он будет анализировать пробел, только если next name_word.В другом случае парсер откатится и переместится на *qi::lit(' '), а затем на запятую.

...