![]() Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Логические операции в регулярных выражениях
В регулярных выражениях perl есть синтаксические выражение, позволяющие в шаблонах использовать простые логические конструкции:
Поиск повторяющихся слов в регулярном выражении осуществляется при помощи т.н. обратных ссылок. Выше уже был приведен пример их использования для выбирания всех адресов рисунков с www.astronomynow.com:
m{SRC\s*=\s*(["'])http://(.*?)\1\s+(.*?)HEIGHT="100"(.*?)>}igs (["']) - найти либо " либо ' либо ничего, т.к. src=http:// может быть без кавычек. Как только был найдено что-либо из этих трех позиций, через минимальное количество символов(регулярное выражение (.*?)) символов оно заносится в специальную переменную \1, которая вне m/.../ может быть вызвана как $1(в s/.../.../ она вызывается в его левую половину как $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-документ, в котором произвольное число вложенных таблиц [<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/.../.../:
|
||
Последнее изменение этой страницы: 2018-04-12; просмотров: 485. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |