Регулярное выражение для подстроки, которой не должен предшествовать символ

Рейтинг: 2Ответов: 1Опубликовано: 22.12.2014

Вроде как нетипичная задача. Выполняю последовательно поиск подстрок в строке и их замену на идентификаторы вида <i#>. Проблема в том, что после одной проверки мне нужно прогнать изменённую строку через выражение "[a-z][a-z0-9]*" (слово из букв и цифр, начинающееся с буквы). Получается, что идентификатор будет повторно распознан и на выходе я получу что-то в духе <<i15>>, что является ошибкой.

Каким образом следует модифицировать выражение "[a-z][a-z0-9]*", чтобы оно не принимало подстроки, перед которыми стоит <. Например:

"as4s" - найдено as4s
"s sd4" - найдено s, sd4
"<asd sad" - найдено sad
"<asd" - ничего не найдено

Ответы

▲ 2Принят

Ни один из диалектов языка регулярных выражений, реализованных в c++11, не поддерживает негативный просмотр назад (с отрицанием) (negative lookbehind): (?<!regex).

Чтобы симулировать (?<!<) можно использовать: (?:^|[^<])\b, что распознаёт либо начало строки либо любой символ отличный от <. При этом \b используется, чтобы не съесть начало идентификатора.

Полный пример:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <regex>
#include <string>

int main()
{
  using namespace std;

  regex re("(?:^|[^<])\\b([a-z][a-z0-9]*)");
  for (const string& s : { "as4s", "s sd4", "<asd",  "<asd sad", } )
    copy(sregex_token_iterator(begin(s), end(s), re, 1),
         sregex_token_iterator(),
         ostream_iterator<string>(cout, "\n"));
}

Результат:

as4s
s
sd4
sad