Изучаем Perl

5c8b6e8c

Еще об операции сопоставления


Выбор другого объекта для сопоставления (операция :='•)

Обычно строка, которую нужно сопоставить с образцом, не находится в переменной $_, и помещать ее туда довольно утомительно. (Может быть, в переменной $__ уже хранится значение, которое вам не хочется терять.) Ничего страшного — здесь нам поможет операция =~. С ее помощью вы можете назначить для проведения операции сопоставления строку, хранящуюся в переменной, отличной от $_.

Эта переменная указывается справа от знака операции. Выглядит это так:

$а = "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"

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



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