Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Регулярные выражения Perl.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
20.18 Кб
Скачать

3. Как выдрать кусок строки?

Символ вертикальной черты (он же «пайп» или просто «палка») в регулярных выражениях означает «или». Например, выражению [a-zA-Z]{20}|[0-9]{25}соответствуют все строки, содержащие 20 символов латинского алфавита или 25 цифр подряд. Обычно этот символ используется совместно с круглыми скобками, предназначенных для группировки частей регулярного выражения. Пример:

if($filename =~ /backup(19|20)[0-9]{2}-[0-9]{2}-[0-9]{2}/) {

# подходит: backup2011-04-01, backup1999-01-13

# не подходит: backup1873-12-12, backup2101-07-07

}

У круглых скобок есть еще одна функция. С их помощью можно выдирать куски соответствующих строк. В PHP результат сохраняется в переменную, указанную третьим аргументом функции preg_match. В Perl совпадения для 1-ой, 2-ой … 9-ой пары скобок сохраняются в переменные $1, $2, …, $9 . Но удобнее использовать такую конструкцию:

if(my ($y, $m, $d) =

$filename =~ /backup([0-9]{4})-([0-9]{2})-([0-9]{2})/) {

print "year = $y, month = $m, day = $d\n";

}

Спрашивается, под каким номером искать совпадение в возвращаемом массиве, если регулярное выражение содержит вложенные скобки? Все просто — совпадения возвращаются в том же порядке, в котором идут открывающиеся скобки. Пример:

my $filename = "./dumps/backup2011-04-01.tgz";

$filename =~ /backup((20|19)[0-9]{2})-([0-9]{2})-([0-9]{2})/;

print "$1, $2, $3, $4\n";

# выведет: 2011, 20, 04, 01

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

if(my ($y, $m, $d) =

$filename =~ /backup((?:20|19)[0-9]{2})-([0-9]{2})-([0-9]{2})/) {

print "year = $y, month = $m, day = $d\n";

}

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

4. Начало и конец строки

Часто бывает полезным обозначить в регулярном выражение место, где должна начинаться и/или заканчиваться строка. Первое делается с помощью символа крышки в начале выражения, второе — с помощью знака доллара в конце. Примеры:

if($text =~ /^[1-9][0-9]*/) {

# текст, начинающийся с десятичной цифры

# подходит: 3, 801403, 6543bebebe

# не подходит: 0275, -123, abc11111

}

if($text =~ /^0x[0-9a-fA-F]{1,8}$/) {

# шестнадцатеричное число в C-нотации

# подходит: 0x5f3759df, 0xDEADBEEF

# не подходит: 0x1234xxx, xxx0x5678, xxx0x9ABCxxx

}

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

Примечание: Если кого-нибудь интересует, что это за «магические числа»0x5f3759df и 0xDEADBEEF, обращайтесь к Википедии.

5. Специальные символы

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

if(my ($name) = $arg =~ /^--name=(.+)$/) {

print "Hello, $name!\n";

}

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

<span>Text <em>text</em> text</span><span>Source: http://eax.me/</span>

Следующий код вернет нам не то, что хотелось бы:

# в регулярном выражении содержится слэш, поэтому

# приходится использовать вместо него другой ограничитель

my ($text) = $data =~ m#<span>(.*)</span>#;

print $text;

# выведет наиболее длинное совпадение:

# Text <em>text</em> text</span><span>Source: http://eax.me/

А вот что произойдет, если отключить жадный разбор (внимание на знак вопроса):

my ($text) = $data =~ m#<span>(.*?)</span>#;

print $text;

# выведет первое совпадение:

# Text <em>text</em> text

Да, следующие строки делают одно и то же:

# обычная запись ...

$text =~ /([0-9]{4})-([0-9]{2})-([0-9]{2})/;

# на самом деле - лишь сокращение оператора m//

$text =~ m/([0-9]{4})-([0-9]{2})-([0-9]{2})/;

# вместо слэша можно использовать разные скобочки:

$text =~ m{([0-9]{4})-([0-9]{2})-([0-9]{2})};

$text =~ m<([0-9]{4})-([0-9]{2})-([0-9]{2})>;

$text =~ m[([0-9]{4})-([0-9]{2})-([0-9]{2})];

$text =~ m(([0-9]{4})-([0-9]{2})-([0-9]{2}));

# или даже такие символы:

$text =~ m!([0-9]{4})-([0-9]{2})-([0-9]{2})!;

$text =~ m|([0-9]{4})-([0-9]{2})-([0-9]{2})|;

$text =~ m#([0-9]{4})-([0-9]{2})-([0-9]{2})#;

# а также крышку, кавычки, двоеточие, запятую, точку, ...

Зачем понадобилось столько способов записи регулярных выражений? Представьте, что выражение содержит слэши, точки, запятые и прочие символы, но не содержит восклицательного знака. Тогда, очевидно, мы не можем использовать для обозначения начала и конца регулярного выражения слэши, точки и так далее, зато восклицательный знак — можем.

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

# экранированная обратным слэшем точка

# означает именно точку, а не "любой символ"

my ($ext) = $fname =~ /\.([a-z0-9]+)$/;

print "file name: $fname, extension: $ext\n";

Кроме того, обратный слэш используется в следующих обозначениях:

  • \t — обозначает символ табуляции (tab)

  • \r и \n — символы возврата каретки (return) и новой строки (new line)

  • \xNN — соответствует символу с ASCII кодом NN, например \x41соответствует заглавной букве A латинского алфавита

  • \s — соответствует пробелу (space), табуляции, символу новой строки или символу возврата каретки

  • \d — означает любую цифру (digit), а точнее — то, что считается цифрой в Юникоде (см слайд номер 102 в этой презентации)

  • \w — означает так называемое «слово» (word), аналог [0-9a-zA-Z_]

В последних трех выражениях запись буквы в верхнем регистре означает отрицание. Например, \D соответствует выражению [^0-9], \W — выражению[^0-9a-zA-Z_], а \S — любому «не пробельному» символу.

Все эти «буквенные» выражения можно использовать внутри квадратных скобок. Например, выражение [a-f\d] полностью эквивалентно [a-f0-9].

Особого внимания заслуживают выражения \b и \B, означающие границу слова (в том же понимании «слова», как и в случае с \w) и отсутствие границы слова соответственно. Например, выражению perl\b соответствует строка «perl rulez!», но не соответствует «perlmonk». С выражением perl\B все с точностью наоборот. Надеюсь, идея ясна.

И еще один пример:

# разбиваем полное имя файла на путь и имя

my($path, $fname) = $full_name =~ /^(.*)\/([^\/]+)$/;

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