Регулярные выражения

Язык, созданный первоначально с главной целью облегчить обработку большого количества отчетов, просто обязан располагать развитыми средствами для работы с текстом. Напомним, что в среде UNIX, из которой вышел язык Perl, средства для обработки текстовых строк имеются в различных утилитах: sed, awk, grep, cut, а командный интерпретатор shell, также обладающий некоторыми средствами для обработки строк, позволяет организовать совместную работу этих утилит, передавая выход одной программы на вход другой через механизм, называемый конвейером. Такой подход требует написания достаточно изощренных сценариев на языке shell в сочетании с обращением к внутренним командам утилит обработки текста sed или awk. Язык Perl, являясь средством создания программ-сценариев, в то же время один обладает всеми возможностями перечисленных утилит и даже их превосходит.
Типичная задача, возникающая при обработке текстового файла, заключается в том, чтобы найти в нем фрагмент, удовлетворяющий заданным условиям, и выполнить над найденным фрагментом некоторую операцию: удалить, заменить на другой фрагмент, извлечь для дальнейшего использования и т. д. Условия поиска можно достаточно просто выразить словами. Например: найти строку, содержащую слово Perl. Или: найти все фрагменты, находящиеся в конце строки и содержащие две цифры, за которыми следует произвольное количество прописных букв. Для формализованной записи подобных условий используются регулярные выражения, позволяющие описать образец, или шаблон поиска при помощи специальных правил. Манипуляции с регулярными выражениями осуществляются при помощи соответствующих операций, которые мы также рассмотрим в этой главе.

Регулярные выражения

Регулярное выражение, по сути, представляет собой набор правил для описания текстовых строк. Сами правила записываются в виде последовательности обычных символов и метасимволов, которая затем в качестве образца используется в операциях поиска и замены текста. Метасимволы — это символы, имеющие в регулярном выражении специальное значение. Пользователи DOS/Windows хорошо знают метасимвол *, используемый для порождения имен файлов и обозначающий любую допустимую последовательность. Регулярные выражения используются многими программами UNIX, в том числе интерпретатором shell. Каждая из них использует свое множество метасимволов. В большинстве случаев метасимволы разных программ совпадают.

Метасимволы

В языке Perl к метасимволам относятся следующие символы:
"\", ".", "^", "$", "|", "[", "]", "(", ")", "*", "+", "?", "{", "}"
Различные метасимволы выполняют в регулярном выражении разные функции, в частности, используются для обозначения одиночного символа или группы символов, обозначают привязку к определенному месту строки, число возможных повторений отдельных элементов, возможность выбора из нескольких вариантов и т. д.
Регулярное выражение, подобно арифметическому выражению, строится с соблюдением определенных правил. В нем можно выделить операнды (элементы) и операции.
Простейшим регулярным выражением является регулярное выражение, состоящее из одного обычного символа. Обычный символ в регулярном выражении представляет самого себя. Соответственно, последовательность обычных символов представляет саму себя и не нуждается в дополнительной интерпретации. Для использования в операциях в качестве образца регулярное выражение заключается между двумя одинаковыми символами-ограничителями. Часто в качестве ограничителя используется символ косая черта (/). Например, образцу /Perl/ будут соответствовать все строки, содержащие слово Perl,
Если в регулярном выражении какой-либо метасимвол требуется использовать в буквальном, а не специальном значении, его нужно экранировать, или маскировать, при помощи другого метасимвола — \. Например, образцу /\\\*/ соответствует фрагмент текста \*. Здесь первый метасимвол \ экранирует второй метасимвол \, а третий метасимвол \ экранирует метасимвол *
Метасимвол . представляет любой одиночный символ, кроме символа новой строки. Так, образцу /./ будет соответствовать любая непустая строка. Если в операциях сопоставления с образцом установлен флаг s, то метасимволу . соответствует также и символ новой строки.
Метасимвол [ используется в конструкции [...] для представления любого одиночного символа из числа заключенных в скобки, то есть он представляет класс символов. Два символа, соединенные знаком минус, задают диапазон значений, например [A-Za-z] задает все прописные и строчные буквы английского алфавита. Если первым символом в скобках является символ ^, вся конструкция обозначает любой символ, не входящий в число перечисленных в скобках. Например, [^0-9] обозначает все нецифровые символы. Ниже мы рассмотрим и другие способы представления классов символов.
Метасимволы ^ и $ используются для задания привязки к определенному месту строки. Метасимвол ^ в качестве первого символа регулярного выражения обозначает начало строки. Метасимвол $ в качестве последнего символа регулярного выражения обозначает конец строки. Например, следующим образцам соответствуют:
/^$/    — пустая строка (начало и конец, между которыми пусто);
/^Perl/ — слово Perl в начале строки;
/Perl$/ — слово Perl в конце строки.
Метасимвол | можно рассматривать как символ операции, задающей выбор из нескольких вариантов (подобно логической операции ИЛИ). Например, образцу /а | b | с/ соответствует фрагмент текста, содержащий любой из символов а, b, с. Если вариантами выбора являются одиночные символы, как в данном примере, то лучше использовать конструкцию, определяющую класс символов, в данном случае [abc]. Но, в отличие от конструкции [...], операция | применима и тогда, когда вариантами выбора являются последовательности символов. Например, образцу /Word|Excel|Windows/ соответствует фрагмент текста, содержащий любое из слов Word, Excel, Windows.
Следующая группа метасимволов служит в качестве коэффициентов, или множителей, определяющих количество возможных повторений отдельных атомарных элементов регулярного выражения.
r*     — нуль и более повторений r;
r+     — одно и более повторений r; 
r?     — нуль или одно повторение r; 
r{n}   — ровно n повторений r; 
r{n,}  — n и более повторений r;
r{n,m} — минимум n, максимум m повторений r.
Атомарные элементы, или атомы, — это простейшие элементы, из которых строится регулярное выражение. Это не обязательно одиночный символ.
Вот несколько примеров использования множителей в регулярных выражениях:
/.*/       — любая строка;
/.+/       - любая непустая строка;
/[0-9]{3}/ — любая последовательность из трех цифр;
/\[+/      — последовательность, состоящая из любого числа символов [.
В первых двух примерах атомом является метасимвол . (точка). В третьем образце в качестве атома выступает конструкция [0-9], определяющая класс цифровых символов. В четвертом образце атом — это пара символов \[, включающая метасимвол \, отменяющий специальное значение следующего за ним метасимвола [. Полный список атомов мы приведем после изучения всех необходимых синтаксических конструкций.
Алгоритм, применяемый в операциях поиска и замены для обработки регулярных выражений, содержащих множители, является «жадным»: он пытается найти для образца, снабженного множителем, максимальный сопоставимый фрагмент текста. Рассмотрим, например, что происходит при поиске в строке: «Скроен колпак не по-колпаковски, надо колпак переколпаковать» фрагмента, удовлетворяющего образцу /.*колпак/.
Алгоритм найдет максимальный фрагмент, удовлетворяющий выражению .* (вся строка без завершающего символа новой строки), затем начнет двигаться назад, отбрасывая в найденном фрагменте по одному символу, до тех пор, пока не будет достигнуто соответствие с образцом. Найденный фрагмент будет иметь вид: «Скроен колпак не по-колпаковски, надо колпак переколпак».
Можно заставить алгоритм работать иначе, снабдив множитель * модификатором ?. В этом случае алгоритм из «жадного» превращается в «ленивый» и будет для образца, снабженного множителем, искать минимальный соответствующий фрагмент. «Ленивый» алгоритм для множителя *? начнет поиск в строке с пустого фрагмента "", добавляя к нему по одному символу из строки до тех пор, пока не достигнет соответствия с образцом. В этом случае найденный фрагмент будет иметь вид: «Скроен колпак». Все сказанное справедливо и для других множителей. Например, в строке "1234567" будет найден:
для образца /\d*/      — максимальный фрагмент "1234567";
для образца /\d+/      — максимальный фрагмент "1234567";
для образца/\d?/       — максимальный фрагмент "1";
для образца /\d{2,5}/  — максимальный фрагмент "12345";
для образца /\d*?/     — минимальный фрагмент "";
для образца /\d+?/     — минимальный фрагмент "1";
для образца /\d??/     — минимальный фрагмент "";
для образца /\d{2,5}?/ — минимальный фрагмент "12".

Метапоследовательности

Символ \, непосредственно предшествующий одному из метасимволов, отменяет специальное значение последнего. Если же символ \ непосредственно предшествует обычному символу, то, напротив, такая последовательность символов во многих случаях приобретает специальное значение. Подобного рода последовательности будем называть метапоследовательностями, Метапоследовательности в регулярном выражении служат, в основном, для представления отдельных символов, классов символов или определенного места в строке, дополняя и иногда дублируя функции метасимволов. Рассмотрим существующие метапоследовательности.
ПРИМЕЧАНИЕ Последовательность \А эквивалентна метасимволу ^ в начале регулярного выражения, а последовательность \Z — метасимволу $ в конце регулярного выражения, за исключением одного случая. Назовем строку, содержащую внутри себя символы новой строки (ASCII 10), мультистрокой. Фактически мультистрока состоит из отдельных строк, разделенных ограничителями — символами новой строки. При выводе мультистрока отображается в виде нескольких строк. Если к мультистроке применяется операция поиска или замены с опцией /m, то последовательности \А и \Z обозначают соответственно начало и конец всей мультистроки, а метасимволам ^ и $ соответствуют еще и границы внутренних строк, образующих мультистроку.

Атомы

Из всех метасимволов, перечисленных в начале параграфа, нам осталось рассмотреть метасимволы ( и ). Они служат для группирования ряда элементов, входящих в состав образца, в один элемент. Например, образцу /(abc)+/ соответствует строка, состоящая из одного или более повторений последовательности abc, в то время как образцу /abc+/ — строка, состоящая из начальных символов ab, за которыми следует один или более символов с.
Теперь мы можем перечислить атомы, из которых строится регулярное выражение.

Реклама