KnigaRead.com/

Михаил Шохирев - Язык программирования Perl

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Михаил Шохирев, "Язык программирования Perl" бесплатно, без регистрации.
Перейти на страницу:

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


$text = "Альбом 'Dire Straits'tГод 1978tВремя 41:21"; $text =~ m{sdddds}; # найдет ' 1978t'


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

Квантификатор (quantifier) - это обозначение числа повторений предыдущего шаблона при поиске соответствия. Количество повторений может задаваться одним или парой десятичных чисел в фигурных скобках:


{n} повторяется точно n раз {n,} повторяется n и более раз {n,m} повторяется от n до m раз включительно


Квантификатор, также иногда называемый множителем, указывается сразу после конструкции в шаблоне, которую нужно повторить несколько раз, например:


/d{5}/ # ровно пять цифр, то есть: ddddd /s{1,}/ # один и более пробельных символов /[A-Z]{1,8}/ # от 1 до 8 заглавных латинских букв


Опишем с применением квантификаторов шаблон для поиска в тексте последовательности, похожей на телефонный номер, в следующем формате:


символ + + код страны: не менее 1 цифры d{1,} открывающая скобка ( ( код города: 3 цифры и более d{3,} закрывающая скобка ) ) номер абонента: от 4 до 7 цифр d{4,7}


Перед знаками "+", "(" и ")" ставится обратная наклонная черта, чтобы они не воспринимались как метасимволы. Вот какое регулярное выражение получится в результате:


m"+d{1,}(d{3,})d{4,7}"


Для наиболее часто встречающихся квантификаторов предусмотрены удобные односимвольные сокращения:


* повторяется 0 или более раз: то же, что {0,} ? повторяется не более 1 раза: то же, что {0,1} + повторяется как минимум 1 раз: то же, что {1,}


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


m/s*w+[-.,;?]+/ # соответствует, например: ' count--;'


Если квантификатор нужно применить к нескольким шаблонам, то нужно сгруппировать шаблоны, заключив их в круглые скобки. Составим регулярное выражение для поиска IP-адреса, которое находит число, состоящее из одной цифры и более (d+), за которой может стоять точка (.?), причем эта последовательность повторяется ровно четыре раза ({4}):


$pattern = '(d{1,3}.)d{1}'; # шаблон для IP-адреса $text = 'address=208.201.239.36,site=www.perl.com'; $text =~ m/$pattern/; # соответствие: '208.201.239.36'


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


my $text = 'Какой хороший компакт-диск!'; $text =~ /.+йs/; # жадный квантификатор # найдено соответствие: 'Какой хороший '


Это произошло потому, что по умолчанию квантификаторы подразумевают максимальную последовательность символов, соответствующих указанному шаблону. Такое поведение квантификаторов называется "жадным" (greedy quantifier). Чтобы заставить квантификатор вести себя не "жадно", а "лениво" (lazy quantifier), нужно поставить сразу после него символ '?'. Тогда квантификатор будет описывать минимальную последовательность символов, соответствующих образцу. Исправленный с учетом этого образец найдет то, что нужно:


$text =~ /.+?йs/; # ленивый квантификатор # найдено соответствие: 'Какой '


Таким же образом можно ограничивать "жадность" и других квантификаторов, заставляя их прекращать поиск как можно раньше, что обычно и требуется в большинстве ситуаций.

Часто нам бывает небезразлично, в каком месте содержимое строки совпадет с шаблоном. Мы бы хотели уточнить: "в начале строки", "в конце слова" и так далее. Для того чтобы более точно задать положение в тексте, где должно быть найдено соответствие, в регулярных выражениях можно указывать так называемые утверждения. Утверждение (assertion) не соответствует какому-либо символу, а совпадает с определенной позицией в тексте. Поэтому их можно воспринимать как мнимые символы нулевого размера. Чаще всего используются следующие утверждения (другие приведены в таблице 8.1):


^ позиция в начале строки $ позиция в конце строки (или перед n в конце строки) b граница слова: позиция между w и W или W и w B любая позиция, кроме границы слова b


Вот пример шаблонов поиска, где уточняется, что нужно проверить наличие числа в определенном месте строки:


$log = '20060326 05:55:25 194.67.18.73 ... 200 797'; print "Число в началеn" if $log =~ /^d+/; print "Число в концеn" if $log =~ /d+$/;


Утверждение, которое используется для фиксирования части образца относительно положения в строке, иногда называется якорем (anchor). Якори применяются, чтобы указать, в каком именно месте строки нужно искать соответствие образцу.

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

[x]. в переменную $` помещается часть строки до найденного соответствия;

[x]. в переменную $& помещается часть строки, соответствующая образцу;

[x]. в переменную $' помещается часть строки после найденного соответствия;

[x]. в переменную $+ помещается последнее найденное совпадение для последнего шаблона в скобках.

Если поиск окончился неудачей, то этим переменным новые значения не присваиваются. Посмотрим на примере, что сохранится в этих переменных после поиска такого соответствия:


$htm= "<A HREF='http://regexp.ru/'>Регулярные выражения</A>"; $htm =~ m|HREF=["'](S+?)["']>|; # поиск URL сайта


При успешном совпадении с шаблоном в специальные переменные будут помещены такие значения:


$` = '<A ' $& = 'HREF='http://regexp.ru/'>' $' = 'Регулярные выражения</A>' $+ = 'http://regexp.ru/'


Значениями этих переменных можно пользоваться при успешном сопоставлении с образцом, например:


print $& if $text =~ m/$pattern/; # выведет соответствие


В регулярном выражении можно указать, что при успешном сопоставлении строки с шаблоном найденные соответствия нужно сохранить для дальнейшей обработки. С этой целью запоминаемые части шаблона нужно заключить в круглые скобки. Это также называется захватом значений. Найденные совпадения для всех заключенных в скобки частей шаблона будут доступны через специальные переменные с именами $1, $2 и так далее. Составим регулярное выражение для поиска и сохранения в служебных переменных информации о сайте в том же тексте:


$pattern = q|HREF=["'](S+?)["']>([^<]+?)</A>|; # шаблон $htm =~ m/$pattern/; # поиск соответствия в $htm # в $1 = 'http://regexp.ru/' # в $2 = 'Регулярные выражения'


Сохраненные совпадения доступны и во время обработки регулярного выражения, но через переменные с именами 1, 2 и так далее. Эти переменные называются обратными ссылками (backreference) на найденные соответствия. Так, например, можно найти два одинаковых слова, стоящих в тексте друг за другом через пробелы (возможно, по ошибке):


my $string = "Уже скоро скоро наступит весна!"; my $pattern = '(S+)s+1'; # (S+) сохранит значение 'скоро' в 1 $string =~ m/$pattern/; # соответствие: 'скоро скоро'


Операция сопоставления, употребленная в списочном контексте, возвращает список найденных соответствий, для которых было предусмотрено сохранение значений. Поэтому удобно сохранять найденные значения в массиве или в списке скалярных переменных. Например, извлечем из текстовой строки последовательность цифр, похожую на время:


my $text = 'Начало в 12:25:00.'; # строка с данными my $pattern = '(dd):(dd):(dd)'; # образец для поиска my @time = $text =~ m/$pattern/; # сохраним в массиве my ($hh, $mm, $ss) = $text =~ m/$pattern/; # и в списке


Можно находить любое количество соответствий образцу в одной операции сопоставления. Это делается с помощью модификатора глобального поиска.

До сих пор операция сопоставления прекращала работу и возвращала результат, когда находилось первое соответствие строки указанному шаблону. Если для операции сопоставления указать модификатор /g (global), то она будет искать в строке все соответствия образцу, организуя неявный цикл обработки регулярного выражения. Например, так можно найти все числа в строке с помощью одного шаблона:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*