Опубликован: 18.06.2007 | Доступ: свободный | Студентов: 1354 / 35 | Оценка: 4.14 / 3.29 | Длительность: 12:44:00
ISBN: 978-5-94774-604-4
Лекция 3:

Дополнительные конструкции в регулярных выражениях

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >

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

В регулярных выражениях 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 не запрещает присваивать этой переменной значение напрямую.

3.7. Задание модификаторов внутри регулярного выражения

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

(? модификаторы )

Например, (?is-mx) - включение режимов i и s и отключение режимов m и x. Область действия этой конструкции начинается сразу после нее и продолжается до следующей закрывающей круглой скобки. Имеется в виду, конечно, "настоящая" скобка, а не литерал \), который эквивалентен коду \x29. Если справа от этой конструкции нет закрывающей скобки, то ее область действия простирается до конца регулярного выражения. Эта закрывающая скобка может принадлежать захватывающей или незахватывающей паре скобок, закрывать условную конструкцию и т.д. Но, конечно, эту установку модификаторов может отменить другая установка тех же модификаторов. В конечном случае имеет действие та установка модификатора, которая находится "ближе" к данному фрагменту регулярного выражения.

Атомарная группировка тоже относится к дополнительным конструкциям, но мы ее уже рассмотрели.

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >
Константин Бражников
Константин Бражников
Россия
Mike .
Mike .
Россия