auto pos = it->prefix().length(); //
pos = pos > 40 ? pos - 40 : 0; //
cout << it->prefix().str().substr(pos) //
<< "\n\t\t>>> " << it->str () << " <<<\n" //
//
<< it->suffix().str().substr(0, 40) //
<< endl;
}
Сам цикл работает, как и прежде. Изменился процесс в цикле for, представленный на рис. 17.2.
Рис. 17.2. Объект класса smatch, представляющий некое соответствие
Здесь происходит вызов функции prefix(), возвращающий объект класса ssub_match, представляющий часть строки file перед текущим соответствием. Чтобы выяснить, сколько символов находится в части строки file перед соответствием, вызовем функцию length() для этого объекта класса ssub_match. Затем скорректируем значение pos так, чтобы оно было индексом 40-го символа от конца префикса. Если у префикса меньше 40 символов, устанавливаем pos в 0, означая, что выведен весь префикс. Функция substr() (см. раздел 9.5.1) используется для вывода от данной позиции до конца префикса.
После вывода символов, предшествующих соответствию, выводится само соответствие с некоторым дополнительным оформлением, чтобы соответствующее слово выделилось в выводе. После вывода соответствующей части выводится до 40 следующих после соответствия символов строки file.
Упражнение 17.17. Измените свою программу так, чтобы она находила все слова в исходной последовательности, нарушающие правило "
Упражнение 17.18. Пересмотрите свою программу так, чтобы игнорировать слова, содержащие сочетание "ei", но не являющиеся ошибочными, такие как "albeit" и "neighbor".
17.3.3. Использование подвыражений
Схема в регулярном выражении зачастую содержит одно или несколько
Например, в схеме для поиска соответствий расширений файлов языка С++ (см. раздел 16.1.2) круглые скобки используются для группировки возможных расширений. Каждый раз, когда альтернативы группируются с использованием круглых скобок, одновременно объявляется, что эти альтернативы формируют подвыражение. Это выражение можно переписать так, чтобы оно предоставило доступ к имени файла, являющемуся той частью схемы, которая предшествует точке:
//
//
//
regex r("([[:alnum:]]+)\\.(cpp|схх|cc)$", regex::icase);
Теперь в схеме два заключенных в скобки подвыражения:
• ([[:alnum:]]+) — представляет последовательность из одного или нескольких символов;
• (cpp|схх|cc) — представляет расширения файлов.
Теперь программу из раздела 16.1.2 можно переписать так (изменив оператора вывода), чтобы выводить только имя файла:
if (regex_search(filename, results, r))
cout << results.str(1) << endl; //
В первоначальной программе для поиска схемы r в строке filename использовался вызов функции regex_search(), а также объект results класса smatch для содержания результата поиска соответствия. Если вызов успешен, выводится результат. Но в этой программе выводится str(1), т.е. соответствие для первого подвыражения.
Кроме информации об общем соответствии, объекты соответствия предоставляют доступ к каждому соответствию подвыражению в схеме. К соответствиям подвыражению обращаются по позиции. Первое соответствие подвыражению, расположенное в позиции 0, представляет соответствие для всей схемы. После него располагается каждое подвыражение. Следовательно, имя файла, являющееся первым подвыражением в схеме, находится в позиции 1, а расширение файла — в позиции 2.
Например, если именем файла будет foo.cpp, то results.str(0) содержит строку "foo.cpp"; results.str(1) — "foo", a results.str(2) — "cpp".
В этой программе требуется часть имени перед точкой, что является первым подвыражением, поэтому следует вывести results.str(1).