Просмотр вперед

Внутри круглых скобок могут быть расположены следующие конструкции:

  • (?=...) — положительный просмотр вперед. Выведем все слова, после которых расположена запятая:
std::regex rgx("\\w+(?=[,])");
std::string str("text1, text2, text3 text4");
std::sregex_iterator istart(str.begin(), str.end(), rgx);
std::sregex_iterator iend;
while (istart != iend) {
   std::cout << istart->str() << ' ';
   ++istart;
} // text1 text2
  • (?!...) — отрицательный просмотр вперед. Выведем все слова, после которых нет запятой:
std::regex rgx("[a-z]+[0-9](?![,])");
std::string str("text1, text2, text3 text4");
std::sregex_iterator istart(str.begin(), str.end(), rgx);
std::sregex_iterator iend;
while (istart != iend) {
   std::cout << istart->str() << ' ';
   ++istart;
} // text3 text4

Рассмотрим небольшой пример. Предположим необходимо получить все слова, расположенные после тире, причем перед тире и после слов должны следовать пробельные символы:

std::regex rgx("\\s\\-([a-z0-9]+)\\s");
std::string str("-word1 -word2 -word3 -word4 -word5");
std::sregex_iterator istart(str.begin(), str.end(), rgx);
std::sregex_iterator iend;
while (istart != iend) {
   std::cout << istart->str(1) << ' ';
   ++istart;
} // word2 word4 

Как видно из примера, мы получили только два слова вместо пяти. Первое и последнее слово не попали в результат, так как расположены в начале и в конце строки. Чтобы эти слова попали в результат, необходимо добавить альтернативные выборы: (^|\\s) — для начала строки и (\\s|$) — для конца строки. Чтобы найденные выражения внутри круглых скобок не попали в результат, следует добавить символы ?: после открывающей скобки:

std::regex rgx("(?:^|\\s)\\-([a-z0-9]+)(?:\\s|$)");
std::string str("-word1 -word2 -word3 -word4 -word5");
std::sregex_iterator istart(str.begin(), str.end(), rgx);
std::sregex_iterator iend;
while (istart != iend) {
   std::cout << istart->str(1) << ' ';
   ++istart;
} // word1 word3 word5 

Первое и последнее слово успешно попали в результат. Почему же слова word2 и word4 не попали в список совпадений? Ведь и перед тире есть пробел, и после слова есть пробел. Чтобы понять причину рассмотрим поиск по шагам. Первое слово успешно попадает в результат, так как перед тире расположено начало строки, и после слова есть пробел. После поиска указатель перемещается, и строка для дальнейшего поиска примет следующий вид:

"-word1 <Указатель>-word2 -word3 -word4 -word5"

Обратите внимание на то, что перед фрагментом –word2 больше нет пробела, и тире не расположено в начале строки. Поэтому следующим совпадением станет слово word3, и указатель снова будет перемещен:

"-word1 -word2 -word3 <Указатель>-word4 -word5"

Опять перед фрагментом –word4 нет пробела, и тире не расположено в начале строки. Поэтому следующим совпадением станет слово word5, и поиск будет завершен. Таким образом, слова word2 и word4 не попадают в результат, поскольку пробел до фрагмента уже был использован в предыдущем поиске. Чтобы этого избежать, следует воспользоваться положительным просмотром вперед (?=...):

std::regex rgx("(?:^|\\s)\\-([a-z0-9]+)(?=\\s|$)");
std::string str("-word1 -word2 -word3 -word4 -word5");
std::sregex_iterator istart(str.begin(), str.end(), rgx);
std::sregex_iterator iend;
while (istart != iend) {
   std::cout << istart->str(1) << ' ';
   ++istart;
} // word1 word2 word3 word4 word5

В этом примере мы заменили фрагмент (?:\\s|$) на (?=\\s|$). Поэтому все слова успешно попали в список совпадений.

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов