Регулярные выражения Perl и их применение

       

Условная конструкция


В регулярных выражениях Perl имеется условная конструкция, которая позволяет сделать выбор подобно операторам if … then или if … then … else … Она имеет такой синтаксис:

(? условие шаблон-да )

или полный вариант

(? условие шаблон-да | шаблон-нет )

Работает эта конструкция так: вначале проверяется условие, и если оно истинно, то вся эта конструкция как бы заменяется на шаблон-да, а если условие ложно, то вместо конструкции подставляется шаблон-нет (если он есть). А если его нет, то на место этой конструкции ничего не подставляется, как будто этой конструкции не было.

После символов (? в реальной программе всегда будет стоять открывающая круглая скобка. Эта скобка не может отделяться пробельными символами от знака вопроса, даже если регулярное выражение записано в свободном формате (с модификатором x).

Шаблон-да и шаблон-нет представляют из себя произвольные регулярные выражения, а условие может иметь следующие значения.

  1. Число в круглых скобках. Тогда оно считается номером каких-то захватывающих скобок. Если захватывающие скобки с данным номером участвовали в совпадении, то условие считается истинным, если нет - ложным. Здесь опять повторю замечание, что участвовать в совпадении и иметь непустое значение - не одно и то же. В операторе '' =~ /(.*)/;

    скобки участвовали в совпадении и переменная $1 получила пустое значение. В операторе

    '' =~ /(.)*/;

    скобки не участвовали в совпадении, хотя поиск также завершился удачно. Но т.к. квантификатор имел значение 0, то переменная $1 не существует (имеет неопределенное значение).

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

    my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>'; if ($text =~ m!<a\s+[^>]*?href\s*=\s* (["'])? # совпадение для разделителя (', " или пусто). Запоминаем его ([^"'>\x20]+) # ссылка (все кроме пробела, ' и ") (?(1)\1) # если был разделитель, то подставляем шаблон для него [^>]*>[^<]+</a>!ix) { print $2 }


    Обратите внимаение, что при появлении квантификатора x изменились ограничители регулярного выражения (c # на !) и внутри класса символов пробел задан как \x20.

  2. Позиционная проверка, четыре варианта которой мы рассматривали. Если проверка возвращает истину, то подставляется шаблон да, иначе подставляется шаблон нет или "пусто" в случае короткого варианта условной конструкции.

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

    $_=' 1234 aaa $12aF $abc $z 1456'; /(?(?=\$|\d) # начало числа? ( # да, начинаем его захват (?(?=\$) # 16-ное число? \$[\da-fA-F]+ # да, подставляем шаблон 16-ного числа (?{ print 'hex ' }) # печатаем префикс hex | \d+ # нет, ставим шаблон 10-ного числа (?{ print 'dec ' }) # печатаем префикс dec ) # конец захвата числа ) # конец вложенного условия (?{ print "$1\n" }) # печатаем само число [^\$\d]* # это не начало числа, пропускаем все до числа )/gx;

    На печать выдается следующее:

    dec 1234 hex $12aF hex $abc dec 1456

    А теперь разберемся, как работает эта программа. В регулярном выражении имеется две условные конструкции, вторая из них вложена в первую (используется в качестве шаблона да). Внешняя условная конструкция имеет такую логику: следующий символ - $ или десятичная цифра? Да - тогда применяем вложенную условную конструкцию, которая разделит десятичные и 16-ные числа. Нет - тогда подставим шаблон [^\$\d]*, который быстро пропустит все до следующего числа.

    Вложенная конструкция тоже имеет полную форму и работает так: если следующий символ - $, то она подставляет шаблон \$[\da-fA-F]+, который соответствует 16-ному числу, а иначе подставляет шаблон \d+ для десятичного числа.

    Кроме того, в первой альтернативе внешней условной конструкции производится захват числа в нумерованную переменную $1, а после шаблонов для каждого типа чисел выводится на печать, соответственно, слово hex или dec. После закрывающей захватывающей скобки выводится само число из $1.



    Может возникнуть вопрос: как будет обрабатываться фрагмент текста $z, который не является числом, но начинается с символа $? В этом случае сработает первая альтернатива из внешней условной конструкции, которая подставит шаблон \$[\da-fA-F]+. Он не совпадет с этим фрагментом, а это будет означать, что все регулярное выражение не совпало с данной позиции. Но благодаря модификатору g, поиск будет продолжаться в цикле со следующей позиции текста (символа z), и все числа будут напечатаны.

    Подробнее о работе модификатора g мы будем говорить, когда будем описывать работу операторов m/…/ и s/…/…/.

  3. Фрагмент кода Perl. Если в качестве условия выступает фрагмент кода Perl, то используется возвращаемое им значение, т.е. результат последнего вычисления. Если он отличен от пустой строки, строки, которая состоит только из числа 0 (0.0), неопределенности и числового нуля, то считается истиной, иначе ложью. Здесь еще скажу, что в Perl есть интересная специальная переменная $^R - результат последнего выполнения кода Perl в регулярном выражении. Здесь слово "последнего" понимается как результат кода, который выполнился последний раз по времени в ходе работы системы поиска соответствия. Т.е. $^R всегда хранит самый "свежий" результат выполнения встроенного кода Perl. Кроме того, при возврате назад за код Perl вычисленное этим кодом значение "забывается" и восстанавливается предыдущее вычисленное значение, т.е. эта переменная автоматически локализуется. В начале работы программы переменная $^R имеет неопределенное значение, а после выхода из оператора поиска или проверки имеет последнее присвоенное ей значение. Кроме того, код Perl, который стоит в части условия условной конструкции, не изменяет значения переменной $^R! Интересно, что Perl не запрещает присваивать этой переменной значение напрямую.



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