m{/usr/bin/perl}
Недаром обилие левых и правых наклонных черт в первом варианте называют "ученическим синдромом зубочисток" (LTS - Learning Toothpick Syndrome). В приводимых до сих пор примерах операцию сопоставления с литералом в качестве образца вполне можно заменить вызовом функции index(). Самое интересное начинается тогда, когда в образце поиска применяются метасимволы для сопоставления с шаблоном.
Очень часто требуется искать в тексте не конкретные строки, а символьные последовательности, определенные приблизительно: "число в скобках", "четвертое слово с начала строки", "список из пар имя = значение, разделенных запятыми" и тому подобное. В таких случаях в качестве аргумента поиска задается шаблон, который описывает такую последовательность. Шаблон - это образец, в котором, помимо литеральных значений, содержатся метасимволы. Метасимволы (metacharacter) - это знаки, имеющие специальное значение при записи образцов. Вот какие метасимволы применяются при записи регулярных выражений:
{} [] () ^ $ . | * + ? \
При необходимости включить в образец поиска один из этих знаков не как метасимвол, а как обыкновенный символ, нужно отменить его особое значение ("экранировать"), поставив перед ним обратную косую черту (backslash):
$text =~ m"\." # содержится ли в тексте точка?
Как метасимвол точка обозначает в регулярном выражении один любой символ, кроме знака перевода новой строки (\n). Например, для поиска похожих слов можно составить такой шаблон:
/само.а./ # соответствуют: 'самовар', 'самокат', 'самосад'...
# НЕ соответствуют: 'самолюб', 'самогон', 'самоход'...
В регулярном выражении можно задать несколько вариантов образца, любой из которых будет считаться соответствием строки образцу. Варианты образца - это набор возможных альтернатив, разделенных знаком "вертикальная черта" ('|'), который называется "метасимвол альтернатив" (alternation metacharacter). Поиск считается успешным, если найдено соответствие любой из альтернатив, например:
$text = 'Черная кошка в темной комнате'; # будем искать здесь
print "Нашли кошку!" if $text =~ /кот|кошка|котенок/;
Сравнение текста с вариантами образца выполняется слева направо, поэтому, если начало альтернатив совпадает, более длинную альтернативу нужно помещать в начало списка вариантов. Иначе всегда будет найдена более короткая. Значит шаблон в предыдущем примере правильнее записать в виде /котенок|кот|кошка/, чтобы в первую очередь поискать котенка, а затем - кота:
$text = 'Черный котенок в темной комнате'; # ищем здесь
print "Нашли котенка!" if $text =~ /кот.нок|кот|кошка/;
Чтобы сделать образец более универсальным, в первой альтернативе литерал заменен на шаблон с метасимволом "точка", чтобы находились соответствия слову "котенок" в любом написании - через "е" и через "ё". Часто применение регулярного выражения с альтернативами выглядит гораздо изящнее, чем длинное условное выражение:
return if $command =~ /exit|quit|stop|bye/i;
Если в образце после выбора из нескольких альтернатив применяются другие шаблоны или литералы, то конструкцию выбора нужно заключить в круглые группирующие скобки. Например:
$lotr =~ /(Bilbo|Frodo) Baggins/; # один из хоббитов
С помощью метасимволов можно обозначить в шаблоне один символ из заданного набора. Для этого нужно определить класс символов, указав в квадратных скобках набор символов, включаемых в класс. Классы символов похожи на шаблон с вариантами, в котором альтернативами могут быть только отдельные символы. Ради примера запишем шаблон для слов, отличающихся первой буквой из указанного набора:
/[вклрт]от/ # соответствуют: 'вот','кот','лот','рот','тот'
Вот пример шаблона с несколькими классами символов, каждый из которых представляет одну букву в последовательности из четырех символов:
/[мс][ул][хо][ан]/ # соответствуют: 'муха', 'слон'
# а также: 'суоа', 'млхн', 'слоа' и так далее
В классе символов вместо перечисления можно указывать диапазон от начального до конечного символа, разделенных минусом:
[0-9] вместо [0123456789]
[A-Z] вместо [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
Указывая несколько диапазонов в одном классе, запишем шаблон для шестнадцатеричной цифры:
/[0-9a-fA-F]/# соответствуют: '5', 'b', 'D' и так далее
Чтобы включить в символьный класс знак '-', нужно поместить его в начале или в конце перечисленных в классе символов или экранировать обратной чертой. Помещенные в символьный класс, все метасимволы (кроме ']') рассматриваются как обычные символы. Поэтому так могут выглядеть шаблоны для поиска знака препинания или одной из скобок:
[-.,;:!?] # знаки препинания
[()[\]{}] # скобки: \] представляет скобку ']'
Иногда требуется выразить понятие "все, кроме указанных символов": для этого в описании класса символов сразу после открывающей квадратной скобки ставится метасимвол отрицания ('^'). Например, так можно записать шаблоны для "любого символа, кроме знаков препинания" или "любого нецифрового символа":
[^-.,;:!?] # все, кроме этих знаков препинания
[^0-9] # не цифры
Чтобы включить в символьный класс символ '^', нужно поставить его не первым в списке символов или отменить его специальное значение с помощью символа '\':
[*^] или так: [\^]
Для сокращенной записи классов символов в регулярных выражениях предусмотрены специальные обозначения, состоящие из латинской буквы с обратной косой чертой перед ней. Вот они:
\d - любая десятичная цифра, то есть [0-9]
\D - любой символ, кроме цифры: [^0-9] или [^\d]
\w - символ, пригодный для записи идентификатора:[a-zA-Z0-9_]
\W - противоположность символа \w, то есть [^\w]