Токенизация текста с использованием регулярного выражения - PullRequest
0 голосов
/ 27 марта 2012

Я забываю регулярные выражения быстрее, чем день рождения моей мамы. Это главная пита. В любом случае, я хотел получить 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, которая приводит к чистому вектору токена (без повторения - т.е. я не хочу, чтобы вложенная группа пыталась удалить пробел).

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

Ответы [ 2 ]

1 голос
/ 27 марта 2012

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

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

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

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

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

0 голосов
/ 28 марта 2012

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

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

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

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

Вот как вы можете сделать это в бусте -

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;
...