Повышение духа слишком жадный - PullRequest
8 голосов
/ 18 марта 2011

Я нахожусь между глубоким восхищением бустом :: духом и вечным разочарованием, что я этого не понимаю;)

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

Дополнительная информация о том, что я хотел бы сделать: цель состоит в том, чтобы проанализировать некоторые псевдо-SQL и пропустить пробелы.В таком выражении, как

select foo.id, bar.id from foo, baz 

, мне нужно трактовать from как специальное ключевое слово.Правило что-то вроде

"select" >> txt % ',' >> "from" >> txt % ',' 

, но оно явно не работает, видит bar.id from foo как один элемент.

#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
int main(int, char**) {
    auto txt = +(qi::char_("a-zA-Z_"));
    auto rule = qi::lit("Hello") >> txt % ',' >> "end";
    std::string str = "HelloFoo,Moo,Bazend";
    std::string::iterator begin = str.begin();
    if (qi::parse(begin, str.end(), rule))
        std::cout << "Match !" << std::endl;
    else
        std::cout << "No match :'(" << std::endl;
}

1 Ответ

10 голосов
/ 18 марта 2011

Вот моя версия с изменениями, помеченными:

#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
int main(int, char**) {
  auto txt = qi::lexeme[+(qi::char_("a-zA-Z_"))];     // CHANGE: avoid eating spaces
  auto rule = qi::lit("Hello") >> txt % ',' >> "end";
  std::string str = "Hello Foo, Moo, Baz end";        // CHANGE: re-introduce spaces
  std::string::iterator begin = str.begin();
  if (qi::phrase_parse(begin, str.end(), rule, qi::ascii::space)) {          // CHANGE: used phrase_parser with a skipper
    std::cout << "Match !" << std::endl << "Remainder (should be empty): '"; // CHANGE: show if we parsed the whole string and not just a prefix
    std::copy(begin, str.end(), std::ostream_iterator<char>(std::cout));
    std::cout << "'" << std::endl;
  }
  else {
    std::cout << "No match :'(" << std::endl;
  }
}

Компилируется и работает с GCC 4.4.3 и Boost 1.4something; выход:

Match !
Remainder (should be empty): ''

Используя lexeme, вы можете избежать условного употребления пробелов, так что txt соответствует только границе слова. Это дает желаемый результат: поскольку за "Baz" не стоит запятая, а txt не использует пробелы, мы никогда не будем случайно потреблять "end".

Во всяком случае, я не на 100% уверен, что это то, что вы ищете - в частности, str пропущены пробелы в качестве иллюстративного примера, или вы как-то вынуждены использовать этот (без пробелов) формат?

Примечание: если вы хотите убедиться, что вы проанализировали всю строку, добавьте проверку, чтобы проверить, если begin == str.end(). Как уже говорилось, ваш код сообщит о совпадении, даже если был проанализирован только непустой префикс str.

Обновление: Добавлена ​​суффиксная печать.

...