Токенизация текста с использованием регулярных выражений boost

Я забываю регулярные выражения быстрее, чем день рождения моей мамы. Это главная ПИТА. Во всяком случае, я хотел RE для анализа строки состояния ответа HTTP и правильного захвата подэлементов. У меня это работает:

  const boost::regex status_line("HTTP/(\\d+?)\\.(\\d+?) (\\d+?) (.*)\r\n");
  std::string status_test1("HTTP/1.1 200 hassan ali\r\n");

  boost::smatch what;
  std::cout << regex_match(status_test1,what, status_line, boost::match_extra) << std::endl;
  std::cout << what.size() << std::endl;

  BOOST_FOREACH(std::string s, what)
  {
    std::cout << s << std::endl;
  }

4-я группа захвата - это то, о чем я суетился, особенно токенизация слов. Но мне это не нужно, так что моя работа сделана. Тем не менее, я все еще хотел бы знать, как токенизировать предложение, разделенное пробелами, которое заканчивается на «\ 0», что приводит к вектору/массиву лишенных слов.

Я не могу заставить работать следующий фрагмент

  const boost::regex sentence_re("(.+?)( (.+?))*");
  boost::smatch sentence_what;
  std::string sentence("hassan ali syed ");

  std::cout << boost::regex_match(sentence,sentence_what,sentence_re, boost::match_extra) << std::endl;

  BOOST_FOREACH(std::string s, sentence_what)
  {
    std::cout << s << std::endl;
  }

он не должен совпадать с "hassan ali syed ", но должен совпадать с "hassan ali syed", и группа захвата должна выводить hassan ali syed (с переводом строки), но выводит hassan syed syed (обратите внимание, пробел в третьем syed<space>syed. Я полагаю, группы захвата не можете работать с рекурсивными сущностями?

Итак, есть ли чистый способ указать задачу токенизации в синтаксисе PCRE, который приводит к чистому вектору токена (без повторения, т. Е. Я не хочу, чтобы вложенная группа пыталась удалить пробелы).

Я знаю, что это не правильный инструмент для работы, дух / lexx или boost::tokenise лучше всего, и я знаю, что это неправильный способ сделать это. в .net при очистке экрана я находил токены в тексте, многократно применяя регулярное выражение к телу, пока не закончатся токены.


person Hassan Syed    schedule 27.03.2012    source источник


Ответы (2)


Это напоминает мне аналогичный вопрос: Захват повторяющихся подшаблонов в регулярном выражении Python.

Если количество слов, разделенных пробелами, ограничено некоторым максимальным количеством токенов, то вы можете просто добавить целую кучу дополнительных подшаблонов, например:

"HTTP/(\\d+?)\\.(\\d+?) (\\d+?) ([^ ]+\s)?([^ ]+\s)?([^ ]+\s)?([^ ]+\s)?\n\r"

Что, конечно, ужасно.

Если вам нужна вложенная группа, я не думаю, что это можно сделать без поддержки «повторяющегося подшаблона» в вашей реализации регулярного выражения (см. нестандартный модуль regex Python, используемый в связанном вопросе). Вы почти конечно, лучше сделать это с помощью элементарных строковых функций - вашего местного эквивалента string.split().

person Li-aung Yip    schedule 27.03.2012
comment
Примечание. Я не являюсь пользователем C++ или Boost::regexp. - person Li-aung Yip; 27.03.2012

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

Вы можете создать одно регулярное выражение из двух частей. Первая часть захватывает определенные группы, вторая фиксирует в одной группе все остальные. Затем вы можете выполнить еще одно рекурсивное регулярное выражение для второй захваченной части.

Примерно так:
(specific)(part)(to)(capture)(all the remaining text)

Затем выполните регулярное выражение while( /(part)/ ) для предыдущего оставшегося захвата текста.

Вот как вы могли бы сделать это в boost -

const string status = "HTTP/1.1 200 hassan ali\r\n";

boost::regex rx_sentence ( "HTTP/(\\d+)\\.(\\d+)\\s+(\\d+)\\s*([^\\s]+(?:\\s+[^\\s]+)*)?.*" );
boost::regex rx_token ( "[^\\s]+" );

if ( boost::regex_match( status, what, rx_sentence) )
{
    std::cout << "\nMatched:\n-----------------\n" << "'" << what[0] << "'" << std::endl;

    std::cout << "\nStatus (match groups):\n-----------------" << std::endl;
    for (int i=1; i < 4; i++)
    {
        std::cout << i << " = '" << what[i] << "'" << std::endl;
    }
    std::cout << "\nTokens (search of group 4):\n-----------------" << std::endl;
    const string token_str = what[4];

    std::string::const_iterator start = token_str.begin();
    std::string::const_iterator end   = token_str.end();

    while ( boost::regex_search(start, end, what, rx_token) )
    {
        string token(what[0].first, what[0].second);
        cout << "'" << token << "'" << endl;
        start = what[0].second;
    }
}
else
    std::cout << "Didn't match" << std::endl;
person Community    schedule 27.03.2012