Поиск

Метасимволы

Во всех примерах этого занятия фрагменты текста, совпавшие с шаблоном, подчеркиваются. Помните, что строка называется соответствующей шаблону, если хотя бы ее часть соответствует этому шаблону. Подчеркивание показывает, какая именно часть совпадает.

Не пропустите следующие разделы и не огорчайтесь, если сразу вы поймете не все, — понимание постепенно придет. Давайте начнем с метасимволов.

Простой метасимвол

Первый метасимвол — это точка (.) Внутри регулярного выражения точка соответствует любому одиночному символу, кроме символа перевода строки. Например, в шаблоне /p.t/ точка означает любой символ. Этому шаблону соответствуют слова pot, pat, pit, carpet, python и pup_tent. Точка заменяет только один символ. Поэтому слова apt и expect шаблону не подходят, поскольку в первом слове между символами р и t нет никакого символа, а во втором — слишком много символов.

Непечатные символы

Ранее вы узнали, что для включения метасимвола в регулярное выражение В виде литерала перед ним необходимо поставить символ обратной косой черты и тогда метасимвол потеряет свою магическую силу:

Если перед обычным символом поставить символ обратной косой черты, он становится метасимволом. Как вы уже знаете из 2-го занятия, "Строительные блоки Perl: числа и строки", некоторые символы в строковых литералах имеют специальное значение, если перед ними стоит символ обратной косой черты. Почти все из них имеют то же значение и в регулярных выражениях, как показано в табл. 6.1.

Квантификаторы

Пока мы лишь рассматривали случай, когда символу шаблона соответствует один символ в строке. Например, в шаблоне /Simon/ символ S соответствует S, i соответствует /, m соответствует т и т.д. Квантификаторы — это метасимволы, используемые для указания количественных отношений между символами в шаблоне и в искомой строке. Квантификатор может быть поставлен после одиночного символа или после группы символов (о группах мы скоро поговорим).

Простейшим квантификатором является метасимвол +. Он означает, что идущий перед ним символ соответствует нескольким идущим подряд таким символам в строке поиска. Количество символов может быть любым (максимально большим в рамках соответствия шаблону), но должен присутствовать хотя бы один символ. Таким образом, шаблону /do+g/ будут:

Действие метасимвола * схоже с действием +. Метасимвол * указывает, что идущий перед ним символ встречается нуль или более раз. Другими словами, шаблон /t*/ будет искать подряд идущие буквы t, но если таких букв вообще нет, поиск все равно будет считаться успешным, т.е. регулярному выражению /car*t/ будут: ...

Еще более ограниченный диапазон действия у метасимвола ?. Предшествующий ему символ должен встречаться нуль или один раз (но не более того). Так, шаблон /c?ola/ означает, что буква с может встретиться один раз или вообще не встретиться. Этот шаблон соответствует любой строке, содержащей символы ola, например cola.

Различие между метасимволами ? и * состоит в том, что, например, шаблону /c?ola/ соответствуют и ola, и cola, но не ccola. Дополнительная буква с не входит в зону совпадения. Шаблону /c*ola/ будут соответствовать и cola, и ola, и ccola, потому что, в отличие от предыдущего шаблона, для совпадения допускается неограниченное количество подряд идущих букв с.

Если возможностей метасимволов +, *, ? вам недостаточно, воспользуйтесь фигурными скобками {} для точного указания количества повторений:

pat {n,m}

Здесь n — минимально допустимое количество повторений, m — максимально допустимое количество повторений, a pat — символ или группа символов, для которых указывается количество повторений. Один из параметров n или m можно опустить, но не оба сразу! Посмотрите на примеры:

В регулярных выражениях часто используют идиому .*. Ей соответствует все, что угодно, например в шаблоне /first.*last/ — это любые символы, находящиеся между двумя словами. Согласно приведенному шаблону, Perl пытается найти слово first,. текст за ним и слово last. Посмотрите действие шаблона на примере следующих строк:

Внимательно посмотрите на третью строку. Совпадение с шаблоном начинается, как и ожидалось, со слова firstДалее совпадение включает слово last и текст дальше до следующего слова last. Здесь метасимвол * следует четвертому правилу, описанному в разделе "Правила игры": находится самая длинная строка, все еще удовлетворяющая шаблону поиска. В случаях, когда требуется отменить действие этого правила, необходимо воспользоваться возможностью минимального соответствия в Perl. За подробной информацией по данному вопросу обратитесь к странице руководства perlre.

Классы символов

Другая типичная задача использования регулярных выражений — поиск, при котором подходит любой символ из определенного набора. Для поиска чисел хорошо иметь шаблон, соответствующий любой цифре, для поиска в списке имен типа Von Beethoven или von Beethoven вам пригодится шаблон "или v, или V".

В регулярных выражениях Perl такая возможность предусмотрена. Речь идет о так называемых классах символов. Классы символов заключаются в квадратные скобки [ ]. Во время поиска все символы в классе рассматриваются как один символ. Внутри класса можно задавать диапазон символов (когда такой диапазон имеет смысл), помещая дефис между границами диапазона. В табл. 6.2 приведено несколько примеров.

Последний пример наиболее интересен. Из него видно, что внутри символьных классов большинство метасимволов теряют свои значения и становятся обыкновенными символами. Поэтому * — это просто литерал.

Если первым символом класса является знак вставки О, то значение выражения инвертируется. Другими словами, такому классу соответствует любой символ, не входящий в класс, например:

Так как в классах символы ], * и - имеют специальное значение, для их использования в классе существуют определенные правила. Литерал " не должен быть первым символом класса. Перед литералом ] должен стоять символ обратной косой черты, например /[аЬс\]]/. Для помещения в класс дефиса (-) достаточно либо поставить его на первую позицию, либо поместить перед ним символ обратной косой черты.

В Perl имеются сокращения для некоторых часто используемых классов. Все эти сокращения состоят из символа обратной косой черты и следующего за ним неметасимвола, как показано в табл. 6.3.

Ниже приведено несколько примеров:

Но будьте внимательны! Последний шаблон не всегда соответствует слову, например символ подчеркивания, окруженный пробелами, также будет считаться словом. Кроме того, с помощью последнего шаблона будут найдены не все слова, а только те, которые окружены пробелами. При этом слова типа don't не будут найдены из-за апострофа. Ниже вам будет предложен гораздо лучший шаблон для поиска слов.

Группировка и альтернация

В регулярных выражениях можно объединять несколько шаблонов, так чтобы найденная строка соответствовала хотя бы одному из них. Это полезно, если, к примеру, необходимо проверить строку на наличие в ней слов dogs или cats. Для решения подобной проблемы служит операция альтернации, которая в регулярных выражениях задается символом |, например:

Альтернация — полезная вешь, но не всегда удобная, если нужно найти большое количество похожих слов. Пусть вам нужно найти одно из слов frog, bog, log, flog или clog, а выражение /frog|bog|log|flog|clog/ кажется вам слишком громоздким. Тогда нужно воспользоваться альтернацией только для начала строки. Вы можете попытаться использовать такой шаблон:

С помощью данного шаблона не удастся добиться требуемого эффекта, потому что Perl не знает, что альтернация касается начальной части строки. Для решения этой проблемы необходимо воспользоваться группировкой регулярных выражений Perl с помощью символов скобок {).

Допускается вложение скобок, а следовательно, и вложение групп. Предыдущий пример можно переписать и так:
.

В контексте списка оператор поиска по шаблону возвращает список частей найденного выражения, соответствующих группам шаблона. Каждая группа возвращает соответствующее ей значение в список, а если групп в шаблоне нет — возвращается просто 1. Вот пример:

В данном случае шаблон соответствует произвольной последовательности символов (она задана в виде первой группы), за которой расположен пробел, слово is, еще один пробел, а затем другая произвольная последовательность символов (она задана в виде второй группы). Значения частей строки поиска, соответствующие группам регулярного выражения, присваиваются элементам списка $fruitи $color, расположенного в левой части оператора присваивания.

Анкеры

Последние два метасимвола (могу поспорить, вы уже думаете: "Когда же они наконец закончатся?!") — это анкеры. С их помощью можно указать, в каком месте строки (в начале или в конце) должно быть найдено соответствие с шаблоном.

Первый из этих анкеров — символ вставки (^). Этот символ^ помешенный в начале регулярного выражения, говорит о том, что соответствие шаблону должно быть найдено в начале строки. Например, /^video/ соответствует слову video, но только если оно находится в начале строки.

Его двойник — символ доллара ($). Этот символ, помещенный в конец регулярного выражения, говорит о том, что соответствие шаблону должно быть найдено в конце строки. Например, /earth$/ соответствует слову earth, но только если оно находится в конце строки. Ниже приведено несколько примеров (табл. 6.4).