Регулярные выражения Perl и их применение

       

Захватывающие и незахватывающие скобки


Поиск соответствия давал бы мало пользы, если бы нельзя было извлекать из текста интересующие нас фрагменты. Для извлечения фрагмента текста часть шаблона (или весь шаблон), который ему соответствует, надо заключить в круглые скобки. Всего в регулярном выражении может быть 99 захватывающих пар скобок. Такие скобки также называют сохраняющими. Если вы не хотите сохранять часть текста, а только группируете подшаблоны, то для этого существуют обычные скобки, которые не сохраняют текст; таких скобок в регулярном выражении может быть 200 пар. Чтобы сделать пару скобок обычной (несохраняющей), надо сразу после открывающей скобки поставить вопросительный знак и двоеточие. Сохраняющие и несохраняющие скобки могут иметь какой угодно уровень вложенности. Сохраняющие скобки нумеруются в порядке появления открывающей скобки от 1 до 99, чтобы за пределами оператора поиска иметь сохраненными нужные фрагменты текста. Текст, сопоставленный подшаблону в первой паре захватывающих скобок, окажется в специальной переменной $1, сопоставленный второй паре захватывающих скобок - в переменной $2 и т.д. до $99.

Разумеется, не обязательно иметь 99 пар скобок, - незадействованные специальные переменные будут иметь неопределенное значение. Обратите внимание, что нумерация начинается не с нуля и что перемнная $0 не имеет отношения к регулярным выражениям, а хранит имя файла выполняемого сценария.

Рассмотрим такой пример: пусть в переменной $text хранится текст для тега a

<a href="http://www.intuit.ru/">Internet-обучение</a>

Нам надо написать регулярное выражение, которое соответствует тегу a и извлекает из него ссылку. Можно написать так:

$text =~ m#<a href="([^"]+)">[^<]+</a>#; print $1;

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

http://www.intuit.ru/

Сначала в регулярном выражении идет литеральный текст

<a href="


который поглотит все, что будет стоять до этой скобки.

Это хорошо, но ведь параметры тега a ключевые, а не позиционные, и параметр href не обязан стоять первым. Тег может быть оформлен так:

<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>

В этом случае наш оператор поиска не найдет соответствия. Надо пропускать символы, пока не встретится href. Это можно сделать с помощью конструкции

.*?

и не забыть поставить модификатор s, потому что тег может располагаться на нескольких строках (после target="_blank" может быть перевод строки), а метасимвол "точка" без этого модификатора не соответствует символу перевода строки (new line).

Эта конструкция будет пропускать все символы, пока не встретится подстрока href. Но вообще говоря, так мы можем выскочить за границу тега >, если в теге не встретится href. Чтобы увеличить надежность нашего регулярного выражения, можно вместо этой конструкции поставить другую:

[^>]*?

Теперь модификатор s можно не ставить.

Еще я советую использовать директиву

use strict;

чтобы транслятор проверял, все ли переменные определены, и параметр w для выдачи предупреждающих сообщений транслятора.

Если вы запускаете скрипт на Web-сервере из браузера, то вставьте также директиву

use CGI::Carp qw(fatalsToBrowser);

чтобы Perl выводил ошибки в браузер, иначе вы будете долго гадать, почему скрипт не работает.

Вот законченная программа, которая "железобетонно" выводит ссылку из тега a:

#!/usr/bin/perl -w use strict;

my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>'; if ($text =~ m#<a\s+[^>]*?href\s*=\s*["']?([^"'> ]+)["']?[^>]*>[^<]+</a>#i) { print $1 }

Если вы будете запускать Perl-программу на сервере Unix, то запоминайте текст в файл без символов возврата каретки \r. В редакторе Far это можно сделать по клавишам <Shift>+<F2>. Если вывод скрипта будет направлен веб-серверу и от него браузеру, то перед первым выводом (оператором print) должна идти команда

print "Content-Type: text/html\n\n";

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



который поглотит все, что будет стоять до этой скобки.

Это хорошо, но ведь параметры тега a ключевые, а не позиционные, и параметр href не обязан стоять первым. Тег может быть оформлен так:

<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>

В этом случае наш оператор поиска не найдет соответствия. Надо пропускать символы, пока не встретится href. Это можно сделать с помощью конструкции

.*?

и не забыть поставить модификатор s, потому что тег может располагаться на нескольких строках (после target="_blank" может быть перевод строки), а метасимвол "точка" без этого модификатора не соответствует символу перевода строки (new line).

Эта конструкция будет пропускать все символы, пока не встретится подстрока href. Но вообще говоря, так мы можем выскочить за границу тега >, если в теге не встретится href. Чтобы увеличить надежность нашего регулярного выражения, можно вместо этой конструкции поставить другую:

[^>]*?

Теперь модификатор s можно не ставить.

Еще я советую использовать директиву

use strict;

чтобы транслятор проверял, все ли переменные определены, и параметр w для выдачи предупреждающих сообщений транслятора.

Если вы запускаете скрипт на Web-сервере из браузера, то вставьте также директиву

use CGI::Carp qw(fatalsToBrowser);

чтобы Perl выводил ошибки в браузер, иначе вы будете долго гадать, почему скрипт не работает.

Вот законченная программа, которая "железобетонно" выводит ссылку из тега a:

#!/usr/bin/perl -w use strict;

my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>'; if ($text =~ m#<a\s+[^>]*?href\s*=\s*["']?([^"'> ]+)["']?[^>]*>[^<]+</a>#i) { print $1 }

Если вы будете запускать Perl-программу на сервере Unix, то запоминайте текст в файл без символов возврата каретки \r. В редакторе Far это можно сделать по клавишам <Shift>+<F2>. Если вывод скрипта будет направлен веб-серверу и от него браузеру, то перед первым выводом (оператором print) должна идти команда

print "Content-Type: text/html\n\n";

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


Содержание раздела