Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Логические операции в регулярных выражениях




 

В регулярных выражениях perl есть синтаксические выражение, позволяющие в шаблонах использовать простые логические конструкции:

  • (?= шаблон) - после этой точки есть фрагмент текста, который соответствует указанному регулярному выражению;
  • (?! шаблон) - после этой точки нет текста, который бы соответствовал указанному регулярному выражению;
  • (?<= шаблон) - перед этой точкой есть фрагмент текста, соответствующий указанному регулярному выражению;
  • (?<! шаблон) - перед этой точкой нет фрагмента текста, соответствующего указанному регулярному выражению;
  • (?#текст) - комментарий. Текст комментария игнорируется;
  • (?:шаблон) или (?модификаторы:шаблон) - группирует элементы шаблона. В отличие от обычных круглых скобок, не создает нумерованной переменной. Например, модификаторы не будет делать различия между строчными и заглавными буквами, однако область действия этого модификатора будет ограничена только указанным шаблоном;
  • (?=шаблон) - "заглядывание вперед". Требует, чтобы после текущей точки находился текст, соответствующий данному шаблону. Такая, конструкция обрабатывается как условие или мнимый символ, поскольку не включается в результат поиска. Например, поиск с помощью команды /w+(?=\s+)/ найдет слово, за которым следуют один или несколько "пробельных символов", однако сами они в результат не войдут;
  • (?!шаблон) - случай, противоположный предыдущему. После текущей точки не должно быть текста, соотносимого с заданным шаблоном. Так, если шаблон w+(?=\s) - это слово, за которым следует "пробельный символ", то шаблон w+(?!\s) - это слово, за которым мет "пробельного символа".
  • (?<=шаблон) - заглядывание назад. Требует, чтобы перед текущей точкой находился соответствующий текст. Так, шаблон (?<=\s)w+ интерпретируется как слово, перед которым имеется пробельный символ (в отличие от заглядывания вперед, заглядывание назад может работать только с фиксированным числом проверяемых символов).
  • (?<!шаблон) - отрицание предыдущего условия. Перед текущей точкой не должно быть текста, соотносимого с заданным шаблоном. Соответственно, от команды /(?<!\s)w+/требуется найти слово, перед которым нет пробельного символа.
  • (?{код}) - условие (мнимый символ), которое всегда выполняется. Сводится к выполнению команд perl в фигурных скобках. Вы можете использовать эту конструкцию, только если в начале сценария указана команда use re 'eval'. При последовательном соотнесении текста и шаблона, когда perl доходит до такой конструкции, выполняется указанный код. Если полного соответствия для оставшихся элементов найти не удалось, то при возврате левее данной точки шаблона вычисления, проделанные с локальными переменными, откатываются назад. (Условие является экспериментальным. В документации, прилагаемой в perl, можно найти довольно детальное рассмотрение (с примерами) работы этого условия и возможных трудностей в случае его применения.)
  • (?>шаблон) - "независимый" или "автономный" шаблон. Используется для оптимизации процесса поиска, поскольку запрещает "поиск с возвратом". Такая конструкция соответствует подстроке, на которую налагается заданный шаблон, если его закрепить в текущей точке без учета последующих элементов шаблона. Например, шаблон (?>а*)аb в отличие от a*ab не может соответствовать никакой строке. Если поставить в любом месте шаблон а*, он съест все буквы а, не оставив ни одной шаблону ab. (Для шаблона а*аb"аппетит" квантификатор * будет ограничен за счет работы поиска с возвратами: после того как на первом этапе не удастся найти соответствие между шаблоном и текстом, perl сделает шаг назад и уменьшит количество букв а, захватываемых конструкцией а*.)
  • (?(условие)шаблон-да|шаблон-нет) или (?(условие)шаблон-да) - условный оператор, который подставляет тот или иной шаблон в зависимости от выполнения заданного условия. Более подробно описан в документации perl.
  • (?модификаторы) - задает модификаторы, которые локальным образом меняют работу процедуры поиска. В отличие от глобальных модификаторов, имеют силу только для текущего блока, то есть для ближайшей группы круглых скобок, охватывающих конструкцию, Например, шаблон ((?i)text) соответcтвует слову "text" без учета регистра.

Поиск повторяющихся слов в регулярном выражении осуществляется при помощи т.н. обратных ссылок. Выше уже был приведен пример их использования для выбирания всех адресов рисунков с www.astronomynow.com:

 

m{SRC\s*=\s*(["'])http://(.*?)\1\s+(.*?)HEIGHT="100"(.*?)>}igs

(["']) - найти либо " либо ' либо ничего, т.к. src=http:// может быть без кавычек. Как только был найдено что-либо из этих трех позиций, через минимальное количество символов(регулярное выражение (.*?)) символов оно заносится в специальную переменную \1, которая вне m/.../ может быть вызвана как $1s/.../.../ она вызывается в его левую половину как $1). Дальше после *.gif|*.jpg|*.bmp и т.д. должен обязательно идти хотябы один пробел \s+, т.к. браузеры воспримут подстроку src=file.gifborder=0 как файл картинки с расширением gifborder=0. Поэтому данное регулярное выражение вполне исправно работает, хотя оно было сделано для сайта, где в img srcставится полный адрес, т.е. начинающийся с http://Для других сайтов придется выстраивать полные пути в ссылках используя base href, если есть или его url. Если нужно найти какое-то по счету совпадение шаблона в строке, то это реализуется примерно так:

 

while($str=~/WHAT/g){$n++}

$n++ while $str=~/WHAT/g;

$n++ while $str=~/(?=WHAT)/g;#для перекрывающихся совпадений

for($n=0; $n=~/WHAT/g; $n++){}

Каждое кратное совпадение

 

(++$n % 6) == 0;

 

Нужное Вам совпадение:

 

$n=($str=~/WHAT/gi)[6]; #допустим шестое

 

Или каждое четное совпадение

 

@mass=grep{$n++ %2==0} /WHAT/gi;

для нечетного нужно написать внутри grep: $n++ %2==1Логические операции внутри регулярных выражений. Если нужно найти последнее совпадение, то можно воспользоваться отрицанием опережающей проверки (?!WHAT):

 

m#PATTERN(?!.*PATTERN)$#

т.е. найти какой-то PATTERN, при этом не должно найтись что-то еще(.*) и PATTERN, т.е. результат - последнее совпадение;

Минимальные квантификаторы *?, +?, ??,{}?

Допустим нужно найти двойку, перед которой не стоит 3 или пробел:

 

print "$1\n" while m%2(?![3\s])gm%;

используется условие по отрицанию, A(?!B): найти А, перед которым не находится В. Чтобы найти двойку, за которой стоит 3 или пробел (\s), то можно воспользоваться:

 

print "$1\n" while m%2(?=[3\s])gm%;

или

 

print "$1\n" while m%2(?![^3\s])gm%;

где используется ^, [^3\s], который значит следующее: в класс символов, которые нужно найти, не входят 3 и пробел, или другими словами найти все кроме 3 и \s.

Допустим, существует HTML-документ, в котором произвольное число вложенных таблиц [&lt;table>.*</table>]. Требуется "вырезать" по очереди самые вложенные таблицы (не содержащие внутри [<table>.*</table>]), и, соответственно, выводить. И так - рекурсивно до конца вырезать изнутри всю таблицу. Ниже представлена программа, реализующая эту задачу при помощи логического оператора (?!...):

 

#!/usr/bin/perl -wT

$file=qq|s<table>aaa bbb

<table>cc<table>ccc

<table> 2<table>bb</table><table>cc</table></table></table>cc

</table>

ddd</table>d

|;

print $file;

&req($file);

sub req {

if($file=~m%(<table>((?!.*<table>).*?)</table>)%igs){

$file=~s%(<table>((?!.*<table>).*?)</table>)%%igs;

print "Virezali --$1--";

&req($file);

}

return $file;

}

 

Продолжаем рассматривать логические операторы в регулярных выражениях на операторах типа OR, AND или NOT.

Регексп истинен, если /AM|BMA/ или /AM/ || /BMA/и если есть перекрытие типа /BMAM/. Также и /AM/ && /BMA/:

 

/^(?=.*AM)(?=.*BMA)/s

Выражение истинно если /AM/и /BMA/совпадают при перекрытии, которое не разрешено:

 

/AM.*BMA|BMA.*AM/s

Выражение истинно, если шаблон /ABC/не совпадает:

 

!~/ABC/

Или

 

/^(?:(?!ABC).)*$/s

Выражение истинно, если ABCне совпадает, а VBN совпадает:

 

/(?=^(?:(?!ABC).)*$)VBN/s

Несовпадение можно проверить несколькими способами:

 

unless($str =~ /MMM/){...}

if(!($str =~ /MMM/)){...}

if($str !~ /MMM/){...}

Для обязательного совпадения в двух шаблонах:

 

unless ($str !~ /MMM/ && $str !~ /BBB/){...}

#или

if ($str =~ /MMM/ && $str =~ /BBB/){...}

Хотябыводном

 

unless ($str !~ /MMM/ || $str !~ /BBB/){...}

#или

if ($str =~ /MMM/ || $str =~ /BBB/){...}

Регулярные выражения - основа работы с операторами m/.../ и s/.../.../, так как они передаются последним в качестве аргументов. Разберемся, как устроено регулярное выражение \b([A-Za-z)+)\b, осуществляющее поиск отдельных слов в строке:

 

$text = "Perl is the subject.";

$text =~/\b([A-Za-z]+)\b/;

print $1;

Выражение \b([A-Za-z]+)\b включает в себя группирующие метасимволы ( и ), метасимвол границы слова \b, класс всех латинских букв [A-Za-z](он объединяет заглавные и строчные буквы) и квантификатор +, который указывает на то, что требуется найти один или несколько символов рассматриваемого класса. Поскольку регулярные выражения, как это было в предыдущем примере, могут быть очень сложными, разберем их по частям. В общем случае регулярное выражение состоит из следующих компонентов:

Совпадение с любым символом

В perl имеется еще один мощный символ - а именно, точка (.). В шаблоне он соответствует любому знаку, кроме символа новой строки. Например, следующая команда заменяет в строке все символы на звездочки (использован модификатор g, обеспечивающий глобальную замену):

 

$text = "Now is the time.";

$text =~ s/./*/g;

print $text;

********************

А что делать, если требуется проверить совпадение именно с точкой? Символы вроде точки (конкретно, \|()[{^$*+?.), играющие в регулярном выражении особую роль) называются, как уже было сказано выше, метасимволами, и если вы хотите, чтобы они внутри шаблона интерпретировались как обычные символы, метасимволу должна предшествовать обратная косая черта. Точно так же обратная косая черта предшествует символу, используемому в качестве ограничителя для команды m/.../, s/.../.../ или tr/.../.../, если он встречается внутри шаблона и не должен рассматриваться как ограничитель. Рассмотримпример:

 

$line = ".Hello!";

if ($1ine =- m/\./) {

print "Shouldn't start a sentence with a perlod!\n";

}

Shouldn't start a sentence with a perlod!

Если нужно найти самый короткий текстовый фрагмент /QQ(.*?)FF/в "QQ ff QQ ff FF", однако оно найдет "ff QQ ff". Шаблон всегда находит левую строку минимальной длины, которая соответствует всему шаблону, т.е. это вся строка в этом примере. Для правильного шаблона нужно воспользоваться логическими операторами в регулярных выражениях: /QQ((?:(?!QQ).)*)FF/, т.е. сначала QQ, потом не QQ, потом FF.

Конструкции (?<=шaблoн)и (?<!шаблон)работают только с шаблонами, соответствующими фиксированному числу символов. Иными словами, в шаблонах, указываемых для (?<=...) и(?<!...), не должно быть квантификаторов.

Эти условия полезны, если нужно проверить, что перед определенным фрагментом текста или после него находится нужная строка, однако ее не требуется включать в результат поиска. Это бывает необходимо, если в коде используются специальные переменные $& (фрагмент, для которого найдено соответствие между текстом и регулярным выражением), $`(текст, предшествующий найденному фрагменту) и $' (текст, следующий за найденным фрагментом). Более гибким представляется применение нумерованных переменных $1, $2, $3, ... в которые заносятся отдельные части найденного фрагмента.

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

 

$text = "Маrу Tom Frank ";

while ($text =~ /\w+(?=\s)/g) {print $& . "\n";}

Маrу

Tom

Frank

Того же результата можно добиться, если заключить в круглые скобки интересующую нас часть шаблона и затем использовать ее как переменную $1:

 

$text = "Mary Tom Frank ";

while ($text =~ /(\w+)\s/g) {

print $1 . "\n";

}

Маrу

Tom

Frank

Следует четко понимать, что вы имеете в виду, когда используете то или иное условие. Рассмотримследующийпример:

 

$text="Mary+Tom";

if($text=~m|(?!Mary\+)Tom|){

print "Tom is without Mary!\n";

}

else{

print "Tom is busy...\n";

}

 

Вопреки нашим ожиданиям, perl напечатает: Tom is without Mary!Это произойдет по следующей причине. Пробуя различные начальные точки входной строки, от которой начинается сопоставление шаблона и текста, pеr1 рано или поздно доберется до позиции, расположенной прямо перед именем "Tom". Условие (?!Маry\+)требует, чтобы после текущей точки не находился текст *Маry+", и это условие для рассматриваемой точки будет выполнено. Далее, perl последовательно проверяет, что после текущей точки следуют буквы "Т", "o" и "m", и это требование также в силе (после проверки условия (?!Маry\+)текущая точка остается на месте). Тем самым найдено соответствие между подстрокой "Тоm" и шаблоном, поэтому команда поиска возвращает значение истина.

Регулярное выражение (?!Mary\+)....Tom, резервирующее четыре символа под текст "Маry+", для приведенного выше случая выведет то, что требовалось, но выдаст ошибочный ответ, если перед именем "Тоm" нет четырех символов:

 

$text="O, Tom! ";

if($text =~ m|(?!Mary\+)....Tom|){

print "Tom is without Mary!\n";

}

else{

print "Tom is busy...\n";

}

Tom is busy...

 

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

 

$text="Mary+Tom";

if($text=~m|(?<!Mary\+)Tom|){

print "Tom is without Mary!\n";

}

else{

print "Tom is busy...\n";

}

Tom is busy...

Вспомнить и написать про строчку вида

 

push @mass, $li unless($li=~m/(([2 .. 12]).*?1995)|(([6 .. 12]).*?2001)|/)

; perldoc perlop [0-9.]

Модификаторы команд m/.../ и s/.../.../

В perl имеется несколько модификаторов, используемых с командами m/.../ и s/.../.../:

  • i - игнорирует различие между заглавными и строчными буквами.
  • s - метасимволу "точка" разрешено соответствовать символам \n.
  • m - разрешает метасимволам ^ и $ привязываться к промежуточным символам \n, имеющимся в тексте. Не влияет на работу метасимволов , \Z и \z.
  • х - игнорирует "пробельные символы" в шаблоне (имеются в виду "истинные" пробелы, а не метасимволы \s и пробелы, созданные через escape-последовательности). Разрешает использовать внутри шаблона комментарии.
  • g - выполняет глобальный поиск и глобальную замену.
  • с - после того как в скалярном контексте при поиске с модификатором g не удалось найти очередное совпадение, не позволяет сбрасывать текущую позицию поиска. Работает только для команды m/.../ и только вместе с модификатором g.
  • о - запрещает повторную компиляцию шаблона при каждом обращении к данному оператору поиска или замены, пользователь, однако, должен гарантировать, что шаблон не меняется между вызовами данного фрагмента кода.
  • е - показывает, что правый аргумент команды s/.../.../ - это фрагменты выполняемого кода. В качестве текста для подстановки будет использовано возвращаемое значение - возможно, после процесса интерполяции.
  • ee - показывает, что правый аргумент команды s/.../.../ - это строковое выражение, которое надо вычислить и выполнить как фрагмент кода (через функцию eval). В качестве текста для подстановки используется возвращаемое значение - возможно, после процесса интерполяции

 










Последнее изменение этой страницы: 2018-04-12; просмотров: 485.

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