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

Метасимволы

Метасимволы делятся на две группы. Одни из них действуют внутри шаблонов вообще, а другие внутри символьных определений.
«()» обозначают начало и конец второстепенного шаблона.
«» — начало и конец символьных определений.
Обратный слеш перед некоторыми буквами означает их служебную функцию, например «\n» означает переход на новую строку, а «\» перед «+-\(){}» означает их реальное значение. ^ в начале символьного определения говорит о том, что выражение не должно содержать таких символов, поэтому шаблон «[^aeiouy]» значит что символ не является гласной.
Вне квадратных скобок те же символы имеют обратное значение: например, знак «\d» означает число, «\D» – все кроме чисел, знак «^» означает начало выражения, а знак $ — конец.
Выражение «{x,y}» , где x и y – числа(x + — то же самое, что и {1,}
* — {0,}
? – {0,1}
«.» означает любой символ, кроме перехода на новую строку. Так для выделения комментариев в C++ подойдет шаблон (/\*.*\*/). Ему соответствует строка, заключенная между «/*» и
«*/».

Альтернатива

Теперь о конкретных случаях. Например, полный номер телефона можно записать так «+7-095-1234567» или «8-095-1234567» не создавать же два шаблона. Для таких случаев и предусмотрены альтернативы, вводимые знаком «|». Итак, «((8|\+7)\-(\d{3})\-(\d{5,}))» и есть нужный шаблон. Поясню: сначала идет выбор между «+7» и «8», далее «-» и трехзначный код, опять «-» и 5 или более цифр.

Проверки(Assertions)

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

«qwe(?=rty)» означает, что после «qwe» следует «rty»
«qwe(?!rty)» означает, что после «qwe» не следует
«rty»

Шаблону «{3,10}(? А строка, соответствующая шаблону «{1,10}(?

Таким образом можно задать и проверку Интернет-адреса, используя шаблон:

((http|ftp)\://((.(?

Сначала идет выбор между строками «http» и «ftp», далее «://». Затем идет последовательность любых символов(не являющихся «/»), завершающаяся точкой и комбинацией из двух трех или четырех букв и цифр (опция (?i) означает, что буква может быть как строчной, так и прописной). Далее идут «/» и любые другие символы. Тоже можно сделать и без конструкции(?

С увеличением длины строки увеличивается и время ее проверки, так шаблон «((\d+)qwe)», примененный к строке «123456789asd» будет работать примерно так:
9 цифр + qwe – не подходит,
8 цифр + qwe – не подходит,
7 цифр + qwe – не подходит,
и так вплоть до 1 цифры. Если строка длиннее, то сервер может просто зависнуть. Для предотвращения такой траты ресурсов и были придуманы одноразовые шаблоны. Вводятся они выражением «>?». Если шаблон «((?>\d+)qwe)» дошел до числа 9 и не удовлетворен результатом, то он не возвращается в начало, а продолжает проверку.

Рекурсивные шаблоны

Вместо создания вложенных шаблонов можно ввести рекурсию, обозначаемую в регулярных выражениях знаком «(?R)». Например шаблон «(\(((?>[^()]+)|(?R))*\))», примененный к строке «(abcd(ef(ghi)» оставит строку «(ghi)». Разберемся:

Сначала открывающаясяся скобка,
Затем последовательность любых символов кроме скобок,
Если попадаем на открывающуюся скобку,
начинаем все заново, пока не встретим закрывающуюся скобку.

Условные шаблоны

Условные шаблоны названы условными, так как они соответствуют какому-либо условию. Они вводятся конструкциями
(?(условие)выражениееслида) и (?(условие)выражениееслида|
выражениееслинет). Вернемся к нашим баранам…… нет, шаблонам. Телефонный номер можно вводить с кодом города и без, тогда используя шаблон»((?(?

Я рассказал лишь о ключевых элементах шаблонов, оставив позади некоторые тонкости, тем не менее, остается ясно, что шаблоны предоставляют огромный контроль над информацией. Любую последовательность символов можно описать используя шаблоны. Единственное, что мешает – это различие форматов. Дело в том, что шаблоны могут
соответствовать стандарту POSIX или PCRE (Perl Compatible Regular Expressions). Хотя особых различий в них нет, разные языки предоставляют свои функции для каждого стандарта, но это уже совсем другая история…

> Регулярные выражения в Perl

Регулярные выражения используются для нахождения шаблонов в строках. Например, для того, чтобы найти в телефонной книге конкретное имя, или,например, все имена, начинающиеся с буквы "a". Работа с регулярными выражениями является одной из самых мощных и полезных, и в тоже время самых сложных для понимания особенностей Perl. Надеемся, что после прочтения этой статьи вы поймете, насколько это мощный и удобный инструмент. Получив некоторый опыт вы сможете использовать эти возможности с большой пользой для себя.

Операторы

Для работы с регулярными выражениями в Perl используются три оператора
- оператор сравнения (matching - m//), оператор подстановки
(substitution s///) и оператор перевода (translation - tr///).

Все три оператора используют переменную $_ по умолчанию, поэтому
дальше, пока не будут представлены операции =~ и!~, будем
пользоваться ею.

Оператор сравнения проверяет, подходит ли проверяемое выражение под
шаблон, и возвращает значение 1, если это так, и значение 0 в
противном случае. Запись этого оператора состоит из буквы m,
разделителя (чаще всего это косая линия - /, но в принципе это может
быть почти любой символ), шаблона и еще одного разделителя (такого же,
как и первый:).

Оператор сравнения
$_ = ;
if (m/hello/) {
print "hello user\n";
}

if ($input{"siteurl"} =~ #http://#) {
print $input{"siteurl"};
}

В этом примере проверяется, есть ли в строке, полученной со
стандартного входа, слово "hello". Если это так (оператор m// вернет
значение 1), то на стандартный выход вернется фраза "hello user".

Примечание:вообще-то символ "m" является необязательным, поэтому
оператор из этого примера может выглядеть просто как /hello/.

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

Оператор подстановки
$_ = "My name is Fred";
# oh no, my name is Jonathan!
s/Fred/Jonathan/;

В этом примере в строке $_ все слова Fred будут изменены на Jonathan.

Оператор перевода также производит подстановку, но несколько другого
характера - он используется для замены отдельных символом некоторыми
другими (определенными) символами. Синтаксис этого оператора похож на
синтаксис оператора подстановки, с тем отличием, что во-первых он
очевидно начинается с букв tr, а между разделителями вставляются не
шаблоны, а группы символов, первая - исходные символы, вторая -
подстановочные, причем соответствующие символы должны стоять на
одинаковых позициях в своих группах - если вы хотите заменить,
например латинскую "m" на кириллическую "м", они должны стоять на
одинаковых местах: "m" - в первой группе символов, "м" - во второй.

Оператор перевода
$_ = "hi.there, my.name.is.jonathan,";
tr/.,/ !/;

В этом примере все запятые будут изменены на восклицательные знаки, а
точки - на пробелы.

Модификаторы

Возможности каждого из этих операторов можно расширить при помощии
модификаторов. Модификаторы - это грубо говоря символы которые
дописываются к оператору (например, так - s/fred/Jonathan/i), говоря о
том, как ему нужно разбирать рабочее значение.

Модификаторы для оператора сравнения:

  • x - позволяет использовать расширенные регулярные выражения;

Модификаторы для оператора подстановки:

  • e - вычисляет подстановочное выражение перед подстановкой;
  • g - находит все найденные подстроки;
  • i - игнорирует регистр символов в строке;
  • m - рассматривает строку как многострочное значение;
  • s - рассматривает строку как однострочое значение;
  • x - позволяет использовать расширенные регулярные выражения.

Модификаторы

$_ = "My name is Fred";
s/fred/Jonathan/i; # My name is Jonathan
s/jonathan/routine()/ie; # My name is

Операции =~ и!~

Операции =~ и!~ позволяют использовать с операторами m//, s/// и
tr/// любые переменные, а не только $_, которая используется этими
операторами по умолчанию.

Оператор =~ выполняет те же функции, что и оператор присваивания "="
(в случае использования с операторами s/// и tr///) и оператор
сравнения "eq" (при использовании с оператором m//).

Операция =~
$name = "my name is Fred";
$name =~ s/fred/Jonathan/ig;

$string = "hello world";
if ($string =~ /hello/i) {
print "helloworlded in this string.";
}

Аналогично, операция!~ используется так же как и операция "ne" (ее
написание подобно операции чисельного сравнения!=), используется
только с оператором сравнения и означает отрицание удовлетворения
шаблону.

Операция!~
$string = "good";
if ($string !~ /bad/) {
print "hey, it"s not too bad yet!";
}

Память

И напоследок - о возможности более удобно работать с результатами
обработки регулярных выражений, а именно о хранении их в отдельных
переменных. Такими переменными являются предопределенные $&, $`, $", и
набор переменных $1, $2, ..., $9.

Переменная $&

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

$string = "error 404."
$string =~ m/\d+/;

Переменные $` и $ "

Эти переменные служат для хранения фрагментов, которые не
удовлетворили шаблону, а именно подстрок, которые стоят до и после
результата соответственно. Другими словами, после операции, например,
сравнения, значение исходой строки разделяется на три части - часть,
которая подошла под шаблон, и фрагменты, которые идут перед ней и
после нее. Эти части и помещаются в переменные $&, $` и $"
соответственно. (Обратите внимание на то, что в первой переменной -
обратная кавычка, а во второй - прямая). Посмотрим на предыдущий
пример.

$string = "error 404."
$string =~ m/\d+/;

$number = $&; # $number содержит "404"
$before = $`; # $before содержит "error"
$after = $"; # $after содержит "."

Переменные $1..$9

Эти переменные служат для хранения фрагментов строки, которые
удовлетворили соответсвующим определенным фрагментам шаблона. В
шаблоне фрагменты выделяются при помощи скобок. Каждому фрагменту
выделяется номер в том порядке, в котором они расположены, и
соответствующая переменная будет содержать его значение.

$string = "this is to be uppercased";
$string =~ s/(upper\w+)/uc($1)/;
# $string = "this is to be UPPERCASED"

$string = "15 apples, 2 foos, 3 bars";
while ($string =~ m/(\d+) (\w+)/g) {
print "$2: $1\n";
}
# Выведет apples: 15
# foos: 2
# bars: 3

Николай Матковский ,
11.05.2006.

Регулярные выражения являются наиболее сложной темой практически для любого программиста: как для новичка, только что начавшего изучать perl, так и для опытного программиста, ранее не встречавшегося с регулярными выражениями. На самом деле, регулярные выражения не так сложны, как может показаться на первый взгляд, просто с самого начала нужно построить правильные аналоги.

Для начала разберемся - что же такое регулярное выражение. По-английски пишется так - Regular Expression (отсюда часто встречается сокращение "regexp" и даже по-русски "регэксп"). Во-первых, не стоит искать смысл в самом термине - это дословный перевод с английского языка, который представляется слишком абстрактным. Но что бы понять по какому принципу работают регулярные выражения, нам и нужно именно что абстрагироваться на уровень предположений. Пример с поиском вхождения подстроки должен быть понятен всем. Но, на самом деле, хотя с помощью регулярных выражений можно легко найти любое вхождение, этот пример не раскрывает всей прелести регэкспов. Лучше вспомните как работает поиск файлов по шаблону (или по маске). Алгоритм подразумевает использование определенных символов (wildcards), которые позволяют как бы закрыть ту часть имени, которая для нас не имеет значения. Однако сами wildcards не используются в именах файлов (что делает алгоритм менее гибким). Так вот, поиск файлов по шаблону позволяет отобрать те имена файлов, которые удовлетворяют заданному условию. При этом, можно указать и точное имя, а можно в каком-то месте имени сделать предположение (с помощью все тех же wildcards). Так вот, регулярные выражения позволяют выполнять аналогичный поиск в пределах некоторой последовательности байт. Добавьте к этому возможность работы с различными частями образованной маски как с отдельными единицами и вы поймете прелесть регэкспов.

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

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

По частям и все сразу

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

Внутри регулярных выражений обитают несколько жадных, многоруких и любопытных существ, не познакомившись с которыми вы не сможете составлять регэкспы. Речь о квантификаторах, мнимых символах, классах и ссылках. Здесь ссылки - это ссылки на найденный текст. Это стандартное определение, но мне оно кажется немного не подходящим. Накопители или контейнеры более удачное определение, так как они фактически содержат в себе часть (или все) совпадения. Под классами подразумеваются наборы символов. Мнимые символы - это утверждения. То есть мнимый символ не является частью искомого значения, но, в нагрузку ко всему прочему, требует что бы выполнялось определенное условие. Квантификатор - это признак повторения шаблона.

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

Пробежимся по шаблону слева-направо. Слэши указывают границы регэкспа, так что их сразу можно выкинуть. Символ ^ относится к мнимым символам. Он привязывает шаблон к началу строки. Что это значит? Это значит, что мы найдем искомое, только в случае если оно находится в начале исходной строки. Элементарно, Ватсон. Смотрим простейший пример

$source = "Pupkin";

$source =~ /^Pupkin/; # Оператор вернет истину, так

# как в $source Pupkin с самого начала

$source = "Vasya Pupkin";

$source =~ /^Pupkin/; # А здесь уже будет ложь, так как перед

# Пупкиным стоит его имя.

Так вот, если убрать из шаблона мнимый символ привязки к началу строки (^), то результатом работы второго оператора то же будет истина. Для самых непонятливых перепишу шаблоны

$source = "Pupkin";

$source =~ /Pupkin/; # Оператор вернет истину, так

# как в $source Pupkin с самого начала

$source = "Vasya Pupkin";

$source =~ /Pupkin/; # Здесь то же будет истина, так как

# Пупкин в строке есть, хотя и не с начала.

# Но ведь и шаблон не требовал Пупкина в начале строки

Теперь понятно, что такое мнимые символы? Просто дополнительное условие, а не часть искомого.

Итак, вернемся к нашим баранам

Слэши мы откинули как ограничители, с привязкой к началу строки то же разобрались. Далее у нас круглые скобки. Вот здесь, круглые скобки имеют то же самое значение, что и вообще в языках программирования - они изменяют приоритет и группируют операторы. Так и здесь - нужно рассматривать все то что в скобках как некое объединение. Сразу замечу, что пара круглых скобок образуют контейнер (или ссылка на найденный текст в стандартном определении).

И что мы видим? У нас два контейнера, разделенных s. s - это специальный символ, указывающий на любой символ из подмножества пробельных (пробел, табуляция, etc...) Уточню. То что у нас между контейнерами указывает на единичный пробельный символ. Мы подошли к самой важной основополагающей - в регулярном выражении (попросту шаблоне) любой символ соответствует самому себе, если только он не является метасимволом со специальным значением. Вот s как раз и относится к таким метасимволам. Признаюсь, что наш пример вообще сплошь и рядом состоит из метасимволов. Да, да, в нем нет ни одного символа, соответствующего самому себе.

Итак, что же мы выяснили? Мы выяснили, что будем искать нечто, состоящее из двух контейнеров, которые разделены между собой единичным пробельным символом. Теперь пора разобраться с содержимым контейнеров. Начнем с правого - он проще. Точка в регэкспе определяет любой символ, кроме символа новой строки (есть некоторые моменты, когда абсолютно любой). Надеюсь, что такое любой символ понятно? Это может быть "1","2","8","D","a","r" или "b" и так далее и тому подобное от кодов с нуля до самого 255.

Ну а теперь, позвольте представить вам... Символ * превращает предыдущую часть шаблона в маленькое прожорливое существо - квантификатор. Этот самый квантификатор сожрет все символы (так как у нас перед этим было указание точка - любой символ) до самого конца строки. Бесплатный сыр только в мышеловке, но квантификатор этого не знает. Мы не зря поместили его в контейнер. После того, как обработка регулярного выражения будет завершена у нас будет контейнер, в котором сохранится все то, что сожрал квантификатор. Так как у нас всего два контейнера, то это контейнер будет у нас под номером два. В последствии мы так и скажем perl - а ну, отдай нам содержимое второго контейнера. Вот так то.

Итак, чего мы достигли? Мы будем искать нечто, состоящее из двух контейнеров, разделенных единичным пробельным символом. Правый контейнер у нас будет содержать всю ту часть строки, которая находится после единичного пробельного символа. После выполнения регулярного выражения мы сможем использовать содержимое правого (ну и левого то же) контейнера по своему усмотрению. Вот такой вывод на данный момент.

Пора приступать к содержимому левого контейнера. Напомню как он выглядит

Квадратные скобки определяют класс символов. Что такое класс символов? Предположим, что искомое не может быть представлено последовательностью символов, то есть подстрокой. Иначе говоря, в примере с Пупкиным мы не можем явно указать

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

Заметьте как удобно - мы не указываем все символы подряд. Мы просто определяем границы с помощью метасимвола - (это как бы даже и не совсем метасимвол, а только в данном случае). Вместо перечисления цифровых символов мы можем записать

Хотя для цифровых символов есть более эффективное решение - метасимвол d. Итак, у нас в левой части определен класс символов. Но какой-то интересный класс получается - вроде привязанный к началу строки. Нет, метасимвол ^ внутри класса указывает на отрицание символов класса. Это значит, что на месте этой части шаблона должен находиться любой символ, не входящий в состав класса. То есть, для примера

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

#!C:/per/bin/perl -w

reg("Vasya Pupkin");

reg(" Vasya Pupkin");

reg("Vasyattpupkin");

print "$1=$1n$2=$2nn" if $_ =~ /([^s]*)s(.*)/;

В результате получится

Теперь давайте разберемся почему и как. Первый тест однозначно попадает под шаблон: Vasya не состоит из пробельных символов, далее следует один пробельный символ (натурально пробел), а Pupkin составляет оставшуюся часть строки. Результат второго теста у нас какой то странный. Первый контейнер у нас оказался пуст, а второй почему то содержит всю строку без ведущего пробела. С чем это связано? Да с тем, что квантификатор * означает ноль или более символов. Так как первым в строке у нас пробельный символ, в правый контейнер, согласно условию, попадает ноль непробельных символов. Далее, пробел то не входит в состав контейнеров. Ну а второй контейнер жрет всю строку до конца. Третий вариант, я думаю, понятен. Я уже говорил, что каждый символ регулярного выражения соответствует единичному. И только квантификаторы позволяют кушать несколько символов одного класса. В шаблоне контейнеры разделены одиночным пробельным символом. В левый контейнер попадает Vasya. Самым законным образом первый пробельный символ (табуляция в примере) пропускается, а правый контейнер кушает все что осталось - в том числе и второй табулятор. Таким образом, получаем Пупкина с ведущей табуляцией.

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

Теперь наше регулярное выражение будет пропускать между именем и фамилией все пробельные символы. Результат должен быть таким.

Осталось выяснить, каким образом правильно интерпретировать значения второго теста. Во-первых нужно избавиться от привязки к началу строки (по моему этот спецсимвол уже успел потеряться в наших примерах:). Итак, шаблон должен обрабатывать ситуации, когда в начале строки может быть один или несколько пробельных символов. Ну это же элементарно, скажете вы, нужно просто добавить в начало шаблона s и сделать из него квантификатор.

/s*([^s]*)s*(.*)/

Поздравляю! Вы прошли вводный курс по регэкспам;)

Про обжору и другие тонкости

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

Смысл его очевиден - искать Пупкина перед которым может быть что то еще. Однако если источник содержит несколько Пупкиных, то квантификатор сожрет все вплоть до последнего Пупкина. Например поиск по этому регэкспу в строке

Vasya pupkin pupkin

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

для корректного поедания "Vasya " из строки "Vasya pupkin pupkin". Далее, конструкции с фигурными скобками позволяют определять границы апетита квантификатора. Внутри фигурных скобок (естественно после самого квантификатора) может быть указано одно или два значения, перечисленных через запятую, которые соответственно определяют пределы жадности. Впомним про спецификатор *. Аналогичный ему + превращает шаблон в обжору, которого не удовлетворяет менее одного совпадения. То есть при использовании + условие отбора является истинным только когда имеются 1 и более совпадений. Заметьте, что верхний предел у нас неопределен и может быть опущен внутри конструкции с фигурными скобками. Если внутри фигурных скобок указать всего одно значение без запятых, то квантификатор сожрет только такую строку, в которой совпадений с шаблоном будет именно указанное количество.

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

Это регулярное выражение будет помещать в контейнер от двух до десяти символов строки. При чем, учитывая жадность, по возможности квантификатор будет вбирать наибольшую строку. То есть если строка длиной 10 или более символов, то в контейнер попадут именно 10, а не 2 и не 5 символов.

$1= Vasya Pupkin

В общем с квантификаторами можно еще много баловаться. Всего рассказать все равно не удасться. Тут только одно средство - практиковаться.

Далее на повестке дня такое понятие как альтернативные шаблоны. Это элементы регулярного выражения, которые позволяют определять несколько вариантов шаблона. Самый наглядный пример это определение протокола в строке URL

Мнимый символ привязки к началу строки может быть помещен и внутри круглых скобок - результат от этого не меняется. Странно, ведь конструкция с круглыми скобками используется для определения алтернатив, ведь она же используется и для группировки в контейнер. Совершенно верно. Альтернативные шаблоны приводят к автоматическому возникновению нового контейнера. Здесь важно не облажаться и правильно определить номер контейнера при извлечении результатов. Контейнер, который был открыт ранее, имеет наименьший номер. Таким образом можно разобраться даже во вложенных контейнерах.

Есть еще одна фича, которая может вам пригодиться. Это, так называемые, дополнительные конструкции. Они позволяют выполнять проверку до или после текущего места в шаблоне, но при этом в сам шаблон не входят. Их описывать я не буду, так как это обычная справочная информация, которая имеется в любой книге по perl. Просто - что бы вы знали.

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

одиночные символы (characters) - он и есть одиночный, чего его комментировать;)

классы символов (character classes) - , [^]

альтернативные шаблоны (alternative match patterns) - (X|X|X)

квантификаторы (quantifiers) - {}, ?, +, *

мнимые символы (assertions) - s, ^, $, etc...

контейнеры (backreferences) - $1,$2,$x

дополнительные конструкции

От теории к практике

В perl имеются три основных оператора которые работают со строками. Это

m// - проверка совпадений (или поиск)

s/// - подстановка

tr/// - замена

Каждый оператор имеет свои свои модификаторы. Для начала рассмотрим для чего нужны все три оператора.

Первый - m// (или просто //) используется для поиска совпадений с указанным шаблоном. Это как раз то, на чем мы тренировались выше. Там же и пример, как можно его использовать. Второй оператор s/// позволяет не только находить определенные участки, совпадающие с заданным шаблоном, но и выполнять неравнозначную подстановку. Фактически, s/// это то же что и m// (даже модификаторы совпадают), но с возможностью произвольной подстановки. Смысл неравнозначной подстановки открывается когда мы обращаемся к третьему оператору tr///. Оператор замены может заменять участки только на равнозначные по длине. Как следствие - он работает быстрее s///. Из всех операторов s/// самый гибкий - он позволяет выполнять все то, что могут m// и tr///. С его помощью можно свернуть горы. Но, за все приходится платить и здесь мы расплачиваемся скоростью. tr/// можно вообще не рассматривать (если конечо вы не фанат скорости). А вот на s/// хочется остановиться поподробнее.

Прежде всего хочу предупредить - не пытайтесь запихать в правую часть оператора s/// (то есть в ту, которая определяет что будем подставлять вместо найденного шаблона) квантификаторы, мнимые символы и вообще всякие другие неопределенности. Все должно быть четко и однозначно. Работа оператора s/// (в прочем как и m///) подразумевает компиляцию на каждом этапе обращения к регулярному выражению. Если вы не ленились (да и так он часто встречается) то уже знаете про модификатор глобального поиска g, который заставляет работать регэксп на протяжении остатка от предыдущего результата и так до конца строки. Так вот, если в правой части разместить имя переменной-контейнера и заюзать регэксп с модификаторами o и g, то наверняка выйдет бардак, так как o запрещает повторную компиляцию шаблона. В общем тут нужно быть предельно внимательным. Еще хочу обратить ваше внимание на модификаторы e и ee. Они позволяют выполнять код непосредственно в процессе работы регулярного выражения. Если у вас очень сложное задание и его очень трудно реализовать в одном регулярном выражении, разбейте их на составные в правой части - и работать будет быстрее и отлаживать проще.

Список литературы

Для подготовки данной работы были использованы материалы с сайта http://prolib.ru/

Регулярные выражения являются наиболее сложной темой практически для любого программиста: как для новичка, только что начавшего изучать perl, так и для опытного программиста, ранее не встречавшегося с регулярными выражениями. На самом деле, регулярные выражения не так сложны, как может показаться на первый взгляд, просто с самого начала нужно построить правильные аналоги.

Для начала разберемся - что же такое регулярное выражение. По-английски пишется так - Regular Expression (отсюда часто встречается сокращение "regexp" и даже по-русски "регэксп"). Во-первых, не стоит искать смысл в самом термине - это дословный перевод с английского языка, который представляется слишком абстрактным. Но что бы понять по какому принципу работают регулярные выражения, нам и нужно именно что абстрагироваться на уровень предположений. Пример с поиском вхождения подстроки должен быть понятен всем. Но, на самом деле, хотя с помощью регулярных выражений можно легко найти любое вхождение, этот пример не раскрывает всей прелести регэкспов. Лучше вспомните как работает поиск файлов по шаблону (или по маске). Алгоритм подразумевает использование определенных символов (wildcards), которые позволяют как бы закрыть ту часть имени, которая для нас не имеет значения. Однако сами wildcards не используются в именах файлов (что делает алгоритм менее гибким). Так вот, поиск файлов по шаблону позволяет отобрать те имена файлов, которые удовлетворяют заданному условию. При этом, можно указать и точное имя, а можно в каком-то месте имени сделать предположение (с помощью все тех же wildcards). Так вот, регулярные выражения позволяют выполнять аналогичный поиск в пределах некоторой последовательности байт. Добавьте к этому возможность работы с различными частями образованной маски как с отдельными единицами и вы поймете прелесть регэкспов.

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

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

По частям и все сразу

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

Внутри регулярных выражений обитают несколько жадных, многоруких и любопытных существ, не познакомившись с которыми вы не сможете составлять регэкспы. Речь о квантификаторах, мнимых символах, классах и ссылках. Здесь ссылки - это ссылки на найденный текст. Это стандартное определение, но мне оно кажется немного не подходящим. Накопители или контейнеры более удачное определение, так как они фактически содержат в себе часть (или все) совпадения. Под классами подразумеваются наборы символов. Мнимые символы - это утверждения. То есть мнимый символ не является частью искомого значения, но, в нагрузку ко всему прочему, требует что бы выполнялось определенное условие. Квантификатор - это признак повторения шаблона.

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

/^([^\s]*)\s(.*)/

Пробежимся по шаблону слева-направо. Слэши указывают границы регэкспа, так что их сразу можно выкинуть. Символ ^ относится к мнимым символам. Он привязывает шаблон к началу строки. Что это значит? Это значит, что мы найдем искомое, только в случае если оно находится в начале исходной строки. Элементарно, Ватсон. Смотрим простейший пример

$source = "Pupkin";

$source =~ /^Pupkin/; # Оператор вернет истину, так

$source = "Vasya Pupkin";

$source =~ /^Pupkin/; # А здесь уже будет ложь, так как перед

# Пупкиным стоит его имя.

Так вот, если убрать из шаблона мнимый символ привязки к началу строки (^), то результатом работы второго оператора то же будет истина. Для самых непонятливых перепишу шаблоны

$source = "Pupkin";

$source =~ /Pupkin/; # Оператор вернет истину, так

# как в $source Pupkin с самого начала

$source = "Vasya Pupkin";

$source =~ /Pupkin/; # Здесь то же будет истина, так как

# Пупкин в строке есть, хотя и не с начала.

# Но ведь и шаблон не требовал Пупкина в начале строки

Теперь понятно, что такое мнимые символы? Просто дополнительное условие, а не часть искомого.

Итак, вернемся к нашим баранам

Слэши мы откинули как ограничители, с привязкой к началу строки то же разобрались. Далее у нас круглые скобки. Вот здесь, круглые скобки имеют то же самое значение, что и вообще в языках программирования - они изменяют приоритет и группируют операторы. Так и здесь - нужно рассматривать все то что в скобках как некое объединение. Сразу замечу, что пара круглых скобок образуют контейнер (или ссылка на найденный текст в стандартном определении).

И что мы видим? У нас два контейнера, разделенных \s. \s - это специальный символ, указывающий на любой символ из подмножества пробельных (пробел, табуляция, etc...) Уточню. То что у нас между контейнерами указывает на единичный пробельный символ. Мы подошли к самой важной основополагающей - в регулярном выражении (попросту шаблоне) любой символ соответствует самому себе, если только он не является метасимволом со специальным значением. Вот \s как раз и относится к таким метасимволам. Признаюсь, что наш пример вообще сплошь и рядом состоит из метасимволов. Да, да, в нем нет ни одного символа, соответствующего самому себе.

Итак, что же мы выяснили? Мы выяснили, что будем искать нечто, состоящее из двух контейнеров, которые разделены между собой единичным пробельным символом. Теперь пора разобраться с содержимым контейнеров. Начнем с правого - он проще. Точка в регэкспе определяет любой символ, кроме символа новой строки (есть некоторые моменты, когда абсолютно любой). Надеюсь, что такое любой символ понятно? Это может быть "1","2","8","D","a","r" или "b" и так далее и тому подобное от кодов с нуля до самого 255.

Ну а теперь, позвольте представить вам... Символ * превращает предыдущую часть шаблона в маленькое прожорливое существо - квантификатор. Этот самый квантификатор сожрет все символы (так как у нас перед этим было указание точка - любой символ) до самого конца строки. Бесплатный сыр только в мышеловке, но квантификатор этого не знает. Мы не зря поместили его в контейнер. После того, как обработка регулярного выражения будет завершена у нас будет контейнер, в котором сохранится все то, что сожрал квантификатор. Так как у нас всего два контейнера, то это контейнер будет у нас под номером два. В последствии мы так и скажем perl - а ну, отдай нам содержимое второго контейнера. Вот так то.

Итак, чего мы достигли? Мы будем искать нечто, состоящее из двух контейнеров, разделенных единичным пробельным символом. Правый контейнер у нас будет содержать всю ту часть строки, которая находится после единичного пробельного символа. После выполнения регулярного выражения мы сможем использовать содержимое правого (ну и левого то же) контейнера по своему усмотрению. Вот такой вывод на данный момент.

Пора приступать к содержимому левого контейнера. Напомню как он выглядит

Квадратные скобки определяют класс символов. Что такое класс символов? Предположим, что искомое не может быть представлено последовательностью символов, то есть подстрокой. Иначе говоря, в примере с Пупкиным мы не можем явно указать

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

Заметьте как удобно - мы не указываем все символы подряд. Мы просто определяем границы с помощью метасимвола - (это как бы даже и не совсем метасимвол, а только в данном случае). Вместо перечисления цифровых символов мы можем записать

Хотя для цифровых символов есть более эффективное решение - метасимвол \d. Итак, у нас в левой части определен класс символов. Но какой-то интересный класс получается - вроде привязанный к началу строки. Нет, метасимвол ^ внутри класса указывает на отрицание символов класса. Это значит, что на месте этой части шаблона должен находиться любой символ, не входящий в состав класса. То есть, для примера

указывает, что здесь может быть любой нецифровой символ. Так и в нашем примере. Ну а с метасимволом \s вы уже знакомы. Учитывая отрицание получаем - любой непробельный символ. Учтите, что класс определяет только множество для соответствия или отрицания, но не множество для отбора. То есть, если у вас класс, то под шаблон попадет только один символ, удовлетворяющий условию. Для того, чтобы отобрать несколько символов нужно использовать квантификатор, что мы и делаем после описания класса символов. Теперь, что бы разобраться для отбора каких строк можно воспользоваться этим шаблоном давайте напишем пример.

#!C:/per/bin/perl -w

reg("Vasya Pupkin");

reg(" Vasya Pupkin");

reg("Vasya\t\tpupkin");

print "\$1=$1\n\$2=$2\n\n" if $_ =~ /([^\s]*)\s(.*)/;

В результате получится

Теперь давайте разберемся почему и как. Первый тест однозначно попадает под шаблон: Vasya не состоит из пробельных символов, далее следует один пробельный символ (натурально пробел), а Pupkin составляет оставшуюся часть строки. Результат второго теста у нас какой то странный. Первый контейнер у нас оказался пуст, а второй почему то содержит всю строку без ведущего пробела. С чем это связано? Да с тем, что квантификатор * означает ноль или более символов. Так как первым в строке у нас пробельный символ, в правый контейнер, согласно условию, попадает ноль непробельных символов. Далее, пробел то не входит в состав контейнеров. Ну а второй контейнер жрет всю строку до конца. Третий вариант, я думаю, понятен. Я уже говорил, что каждый символ регулярного выражения соответствует единичному. И только квантификаторы позволяют кушать несколько символов одного класса. В шаблоне контейнеры разделены одиночным пробельным символом. В левый контейнер попадает Vasya. Самым законным образом первый пробельный символ (табуляция в примере) пропускается, а правый контейнер кушает все что осталось - в том числе и второй табулятор. Таким образом, получаем Пупкина с ведущей табуляцией.

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

1. Введение

Пара слов для тех, кто не совсем в курсе, о чем идет речь. Вы видели когда-нибудь маски имен файлов — всякие там *.html, filename.{txt|csv} и тд? Так вот, регулярные выражения — это те же «маски», только более сложные. В умелых руках регулярные выражения могут быть невероятно мощным инструментом . Так или иначе они используются в 95% моих скриптов.

Многие небезосновательно считают, что регулярные выражения — это скорее самостоятельный язык программирования, чем часть какого-либо языка. Регулярные выражения есть в Perl, PHP, Python , JavaScript, конфигурационных файлах Apache… В зависимости от языка, могут иметь место небольшие различия в синтаксисе регулярных выражений, но основные идеи везде одни и те же.

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

if (preg_match ("//" , $text ) ) {
// в тексте есть цифры
} else {
// в тексте нет ни одной цифры
}

и такой — на Perl:

if ($text =~ // ) {
# в тексте есть цифры
} else {

}

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

2. Простые примеры

Как всегда, учиться будем на примерах. Квадратные скобки в регулярных выражениях означают «здесь должен быть один из перечисленных символов». Например, приведенному выше выражению соответствует любая строка, содержащая хотя бы одну цифру. Аналогично, выражению соответствует любая строка, содержащая хотя бы одну из первых трех букв латинского алфавита. Чтобы обозначить любой символ, кроме заданных, используется запись [^abcdef] , то есть с символом крышки сразу за открывающейся квадратной скобкой.

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

if ($text =~ // ) {
# в тексте есть цифры
} else {
# в тексте нет ни одной цифры
}

И еще пара примеров:

if ($text =~ // ) {
# в тексте есть цифры и/или строчные буквы
# подходит: abc, ZZaZZ, ===17
# не подходит: EPIC FAIL, @^*!@#
}

if ($text =~ /[^0-9]/ ) {
# в тексте есть символы, отличные от цифр
# подходит: abc, 123abc456, 0x1111111111
# не подходит: 123, 123456, 9999999999
}

if ($text =~ // ) {
# в тексте есть буквы латинского алфавита
# подходит: ___Abba___, zyx
# не подходит: 0123, ^_^
}

if ($text =~ // ) {
# текст содержит цифры и буквы от A до F
# подходит: ***777***, DeadC0de, intel, 0_o
# не подходит: Xor, wiki
}

Усложним задачу. Теперь нам нужно проверить не просто наличие или отсутствие определенных символов, а соответствие строки определенному формату. Вот несколько простых примеров:

if ($text =~ /num=/ ) {
# подходит: num=1, some_num=000, bebenum=2(&^*
# не подходит: NUM=1, my_num=-1, num=abc
}

if ($text =~ // ) {
# подходит:
# zzzzzz
#
# не подходит:
#
#
}

Внимательный читатель поинтересуется, что это за знак плюса стоит в последнем регулярном выражении? Этот символ означает «один или более символов, указанных перед этим плюсом». Почти то же самое обозначает символ звездочка «от нуля до сколько угодно символов, указанных перед звездочкой». Например, выражению A+ будет соответствовать последовательность из одного и более символов A, а выражению * — любое количество цифр, в том числе и ни одной.

Иногда количество символов нужно задать точнее. Это можно сделать с помощью фигурных скобок . Например, выражению {8} соответствует любая последовательность из ровно восьми цифр, а выражению {3,8} — последовательность, содержащая от 3-х до 8-и символов латинского алфавита.

Число на второй позиции можно не указывать. То есть выражение {3,} также может иметь место. Оно означает «не менее трех строчных букв латинского алфавита». Выражение {0,} полностью аналогично звездочке, а {1,} — плюсу. Выражение {0,1} можно записать более коротко, используя знак вопроса .

Пример (не самый простой, зато интересный):

if ($text =~ // ) {
# подходит:
# dfgddfgdfg
#
# не подходит:
#
#
}

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

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

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

if ($filename =~ /backup(19|20){2}-{2}-{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({4})-({2})-({2})/ ) {
print ;
}

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

my $filename = "./dumps/backup2011-04-01.tgz" ;
$filename =~ /backup((20|19){2})-({2})-({2})/ ;
print "$1, $2, $3, $4\n " ;
# выведет: 2011, 20, 04, 01

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

if (my ($y , $m , $d ) =
$filename =~ /backup((?:20|19){2})-({2})-({2})/ ) {
print "year = $y, month = $m, day = $d\n " ;
}

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

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

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

if ($text =~ /^*/ ) {
# текст, начинающийся с десятичной цифры
# подходит: 3, 801403, 6543bebebe
# не подходит: 0275, -123, abc11111
}

if ($text =~ /^0x{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 > Source: http://сайт/</ span >

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

# в регулярном выражении содержится слэш, поэтому
# приходится использовать вместо него другой ограничитель
(.*)#;
print $text ;
# выведет наиболее длинное совпадение:
# Text text textSource: http://сайт/

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

my ($text ) = $data =~ m #(.*?)#;
print $text ;
# выведет первое совпадение:
# Text text text

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

# обычная запись...
$text =~ /({4})-({2})-({2})/ ;
# на самом деле - лишь сокращение оператора m//
$text =~ m/({4})-({2})-({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 #({4})-({2})-({2})#;
# а также крышку, кавычки, двоеточие, запятую, точку, ...

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

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

# экранированная обратным слэшем точка
# означает именно точку, а не "любой символ"
my ($ext ) = $fname =~ /\.(+)$/ ;
print "file name: $fname, extension: $ext\n " ;

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

  • \t — обозначает символ табуляции (t ab)
  • \r и \n — символы возврата каретки (r eturn) и новой строки (n ew line)
  • \xNN — соответствует символу с ASCII кодом NN, например \x41 соответствует заглавной букве A латинского алфавита
  • \s — соответствует пробелу (s pace), табуляции, символу новой строки или символу возврата каретки
  • \d — означает любую цифру (d igit), а точнее — то, что считается цифрой в Юникоде (см слайд номер 102 в этой презентации)
  • \w — означает так называемое «слово» (w ord), аналог

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

Все эти «буквенные» выражения можно использовать внутри квадратных скобок. Например, выражение полностью эквивалентно .

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

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

# разбиваем полное имя файла на путь и имя
my ($path , $fname ) = $full_name =~ /^(.*)\/([^\/]+)$/ ;

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

6. Модификаторы

Поведение регулярных выражений можно менять с помощью модификаторов. Например, как вы уже могли заметить, соответствие строки регулярному выражению проверяется с учетом регистра символов. Изменить это поведение можно с помощью модификатора #(.*?)#g;
# будьте осторожны при использовании /g в скалярном контексте
# подробности здесь: http://koorchik.blogspot.com/2011/07/perl-5.html
print "$_\n " for (@words ) ;

Как было сказано выше, точка обозначает любой символ, кроме символа новой строки . Изменить такое поведение можно с помощью модификатора /s :

# выдираем из HTML-файла содержимое статьи,
# которое может содержать далеко не одну и не две строчки
my ($article ) = $html =~ m #

(.*?)
#s;

Кстати, если в регулярном выражении нужно обозначить «любой символ» без использования модификатора /s , используйте выражение [\d\D] . Оно означает «любой символ, являющийся цифрой, или не являющийся цифрой», то есть вообще любой символ.

Наконец, ничто не мешает использовать несколько модификаторов одновременно:

# выдираем из HTML-файла все, что выделено жирным
my @words = $html =~ m #(.*?)#gi;
# сработает для , или даже

Дополнение: Еще один полезный модификатор — /o . Он означает «компилировать регулярное выражение только один раз». В некоторых случаях этот модификатор может существенно ускорить скрипт. Правда, я не уверен, что он поддерживается где-то, кроме как в Perl. За наводку спасибо товарищу