Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
// тот же заголовок цикла for, что и прежде
for (sregex_iterator it(file.begin(), file.end(), r), end_it;
it != end_it; ++it) {
auto pos = it->prefix().length(); // размер префикса
pos = pos > 40 ? pos - 40 : 0; // необходимо до 40 символов
cout << it->prefix().str().substr(pos) // последняя часть префикса
<< "ntt>>> " << it->str() << " <<<n" // соответствующее
// слово
<< it->suffix().str().substr(0, 40) // первая часть суффикса
<< endl;
}
Таблица 17.10. Операции с типом smatch
Эти операции применимы также к типам cmatch, wsmatch, wcmatch и соответствующим типам csub_match, wssub_match и wcsub_match. m.ready() Возвращает значение true, если m был установлен вызовом функции regex_search() или regex_match(), в противном случае — значение false (в этом случае результат операции с m непредсказуем) m.size() Возвращает значение 0, если соответствия не найдено, в противном случае — на единицу больше, чем количество подвыражений в последнем соответствующем регулярном выражении m.empty() Возвращает значение true, если размер нулевой m.prefix() Возвращает объект класса ssub_match, представляющий последовательность перед соответствием m.suffix() Возвращает объект класса ssub_match, представляющий часть после конца соответствия m.format(...) См. табл. 17.12 В функциях, получающих индекс, n по умолчанию имеет значение нуль и должно быть меньше m.size(). Первое соответствие (с индексом 0) представляет общее соответствие. m.length(n) Возвращает размер соответствующего подвыражения номер n m.position(n) Дистанция подвыражения номер n от начала последовательности m.str(n) Соответствующая строка для подвыражения номер n m[n] Объект ssub_match, соответствующий подвыражению номер n m.begin(), m.end() m.cbegin(), m.cend() Итераторы элементов sub_match в m. Как обычно, функции cbegin() и cend() возвращают итераторы const_iteratorБолее подробная информация о smatch и ssub_match приведена в следующем разделе, а пока достаточно знать, что они предоставляют доступ к контексту соответствия. У типов соответствия есть функции-члены prefix() и suffix(), возвращающие объект класса ssub_match, представляющий часть исходной последовательности перед и после текущего соответствия соответственно. У класса ssub_match есть функции-члены str() и length(), возвращающие соответствующую строку и ее размер соответственно. Используя эти функции, можно переписать цикл программы проверки правописания:
// тот же заголовок цикла for, что и прежде
for (sregex_iterator it(file.begin(), file.end(), r), end_it;
it != end_it; ++it) {
auto pos = it->prefix().length(); // размер префикса
pos = pos > 40 ? pos - 40 : 0; // необходимо до 40 символов
cout << it->prefix().str().substr(pos) // последняя часть префикса
<< "ntt>>> " << 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.3.2Упражнение 17.17. Измените свою программу так, чтобы она находила все слова в исходной последовательности, нарушающие правило "i перед е, кроме как после с".
Упражнение 17.18. Пересмотрите свою программу так, чтобы игнорировать слова, содержащие сочетание "ei", но не являющиеся ошибочными, такие как "albeit" и "neighbor".
17.3.3. Использование подвыражений
Схема в регулярном выражении зачастую содержит одно или несколько подвыражений (subexpression). Подвыражение — это часть схемы, которая сама имеет значение. Для обозначения подвыражения в регулярном выражении, как правило, используют круглые скобки.
Например, в схеме для поиска соответствий расширений файлов языка С++ (см. раздел 16.1.2) круглые скобки используются для группировки возможных расширений. Каждый раз, когда альтернативы группируются с использованием круглых скобок, одновременно объявляется, что эти альтернативы формируют подвыражение. Это выражение можно переписать так, чтобы оно предоставило доступ к имени файла, являющемуся той частью схемы, которая предшествует точке:
// r содержит два подвыражения:
// первое - часть имени файла перед точкой,
// второе - расширение файла
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).
Подвыражения для проверки правильности данныхПодвыражения обычно используются для проверки данных, которые должны соответствовать некоему определенному формату. Например, в Америке номера телефонов имеют десять цифр, включая код города и местный номер из семи цифр. Код города зачастую, но не всегда, заключен в круглые скобки. Остальные семь цифр могут быть отделены тире, точкой или пробелом либо не отделяться вообще. Данные в некоторых из этих форматов могли бы быть приемлемы, а в других — нет. Процесс будет состоять из двух этапов: сначала используем регулярное выражение для поиска последовательностей, которые могли бы быть номерами телефонов, а затем вызовем функцию для окончательной проверки правильности данных.