Еще об операции сопоставления
Выбор другого объекта для сопоставления (операция :='•)
Обычно строка, которую нужно сопоставить с образцом, не находится в переменной $_, и помещать ее туда довольно утомительно. (Может быть, в переменной $__ уже хранится значение, которое вам не хочется терять.) Ничего страшного — здесь нам поможет операция =~. С ее помощью вы можете назначить для проведения операции сопоставления строку, хранящуюся в переменной, отличной от $_.
Эта переменная указывается справа от знака операции. Выглядит это так:
$а = "hello world";
$а =~ /^he/; # истина
$а =~ /(.)\1/; # тоже истина (соответствует двум 1)
if ($а =~ /(.)\1/) ( t истина, поэтому проводятся дальнейшие операции
1
Справа от знака операции =~ может стоять любое выражение, которое дает в результате некоторое скалярное строковое значение. Например, <stdin> при использовании в скалярном контексте дает скалярное строковое значение, поэтому, объединив эту операцию с операцией =~ и операцией сопоставления с регулярным выражением, мы получим компактную программу проверки входных данных:
print "any last request? ";
if (<STDIN> ==~ /л[y1}/) { # начинаются ли входные данные с буквы у? print "And just what might that request be? ";
# и чтобы это мог быть за запрос? <STDIN>; # получить строку со стандартного ввода print "Sorry, I'm unable to do that.\n";
# прошу прощения, но я не могу этого сделать )
В данном случае при помощи <stdin> берется очередная строка со стандартного ввода, которая затем сразу же используется как строка, сопоставляемая с образцом л [ yY ]. Отметим, что мы не сохраняли входные данные в переменной, поэтому если мы захотим сопоставить эти данные с другим образцом или же вывести их в сообщении об ошибке, то у нас ничего не выйдет. Тем не менее эта форма часто оказывается удобной.
Игнорирование регистра
В предыдущем примере мы указывали образец [yY] для обозначения строчной и прописной буквы у. Если речь идет об очень коротких строках, например, у или fred, то данный способ обозначения достаточно удобен, скажем, [fF] [rR] [eE] [dD]. А что делать, если сопоставляемая строка — это слово procedure в нижнем или верхнем регистре?
В некоторых версиях grep флаг -i означает "игнорировать регистр". В Perl тоже есть такая опция. Чтобы ею воспользоваться, нужно добавить строчную i к закрывающей косой черте, т.е. написать / образец/i. Такая запись говорит о том, что буквы образца будут соответствовать буквам строки в любом регистре. Например, чтобы найти слово procedure в любом регистре, стоящее в начале строки, запишите /^procedure/i.
Теперь наш предыдущий пример будет выглядеть так:
print "any last request? ";
if (<STDIN> =~ /"y/i) { # начинаются ли входные данные с буквы у? # да! выполнить какие-то операции
…
}
Использование другого разделителя
Чтобы найти строку, которая содержит несколько косых (/), в соответствующем регулярном выражении нужно перед каждой из них поставить обратную косую черту (\). Например, чтобы найти строку, которая начинается с названия директории /usr/etc, нужно записать:
$path = <STDIN>; # прочитать путевое имя (вероятно, из find?) if ($path =~ /"VusrVetc/) {
# начинается с /usr/etc... }
Как видите, комбинация "обратная косая — косая" создает между элементами текста своеобразные "проходы". Если косых очень много, это занятие может стать весьма утомительным, поэтому в Perl предусмотрена возможность использования другого разделителя (delimiter). Поставьте перед любым специальным символом* (выбранным вами в качестве разделителя) букву т, укажите свой образец и дайте еще один такой же разделитель:
/''•VusrVetc/ # использование стандартного разделителя — косой черты m@^/usr/etc@ # использование в качестве разделителя символа @ m#^/usr/etc# # использование в качестве разделителя символа # # (это мой любимый символ)
Если хотите, можете опять использовать косые, например, m/fred/. Таким образом, m — общепринятое обозначение операции сопоставления с регулярным выражением, но если в качестве разделителя выбрана косая черта, то m не обязательна.
Использование интерполяции переменных
Перед тем как регулярное выражение рассматривается на предмет наличия специальных символов, в нем производится интерполяция переменных. Следовательно, регулярное выражение можно строить не только из литералов, но и из вычисляемых строк. Например:
$what = "bird";
$sentence = "Every good bird does fly.";
if ($sentence =~ /\b$what\b/) {
print "The sentence contains the word $what!\n";
>
Здесь мы использовали ссылку на переменную для построения операции сопоставления с регулярным выражением \bbird\b/.
* Если этот разделитель — левый элемент пары (круглая, фигурная, угловая или квадратная скобка), то закрывающим разделителем будет соответствующий правый элемент пары. В остальных случаях первый и второй разделители будут совпадать.
Вот несколько более сложный пример:
$sentence = "Every good bird does fly.";
print "What should I look for? ";
$what = <STDIN>;
chomp($what) ;
if ($sentence =~ /$what/) ( # нашли! print "I saw $what in $sentence.\n";
} else (
print "nope... didn't find it.\n";
)
Если вы введете слово bird, оно будет найдено, а если слово scream — не будет. Если ввести [bw] ird, результаты поиска тоже будут успешными. Это говорит о том, что квадратные скобки в данном случае воспринимаются как символы сопоставления с образцом.
Чтобы избежать этого, следует поставить перед этими символами обратную косую, которая превратит их в символы буквального сопоставления. Это кажется сложным, если в вашем распоряжении нет закавычивающей управляющей последовательности \Q:
$what = "[box]";
foreach (qw(in([box] out [box] white [sox] ) ) { if (/\Q$what\E/) {
print "$_ matched!\n";
1 }
Здесь конструкция \Q$what\E превращается в \[box\], в результате чего операция сопоставления ищет пару квадратных скобок, а не рассматривает всю конструкцию как класс символов.
Специальные переменные, защищенные от записи
После успешного сопоставления с образцом переменным $1, $2, $3 и т.д. присваиваются те же значения, что и \1, \2,\3 и т.д. Это можно использовать для поиска соответствия в последующем коде. Например:
$_ = "this is a test";
/(\w+)\W+(\w+)/; # сопоставление первых двух слов
# $1 теперь содержит this, а $2 — is
Доступ к тем же значениям ($1, $2, $3 и т.д.) можно также получить, использовав операцию сопоставления для соответствующих списков. Если результаты сопоставления окажутся положительными, будет получен список значений от $1 до $п (где n — количество занесенных в память элементов). В противном случае значения не определены. Запишем последний пример по-другому:
$_ = "this is a test";
($first, $second) = /(\w+)\W+(\w+)/; # сопоставление первых двух слов # $first теперь содержит this, a $second - is
К другим предопределенным защищенным от записи переменным относятся: $& (часть строки, совпавшая с регулярным выражением); $' (часть строки, стоящая перед совпавшей частью); $ ' (часть строки, стоящая после совпавшей части). Например:
$_ = "this is a sample string";
/sa.*le/; # соответствует слову sample внутри строки
# $' теперь содержит "this is a "
# $& теперь содержит "sample"
# $' теперь содержит "string"
Поскольку значения этим переменным присваиваются при каждом успешном сопоставлении, их нужно где-нибудь сохранить, если они вам впоследствии понадобятся*.