Если на компьютере у читателя еще не установлена система программирования
m/…/ и замены s/…/…/. Слово регулярные означает "составленные по правилам". То, что стоит вместо многоточия в операторе m и вместо первого многоточия в операторе s, - это и есть m означает match (соответствие), а буква s означает substitution (замена)
Предположим, в программе проверяется ввод пользователя, чтобы выяснить, хочет ли он завершить программу, введя слова stop, quit, exit или abort. Без регулярных выражений вам пришлось бы использовать ряд сравнений с этими образцами, предварительно преобразовав ввод к нижнему регистру. С оператором m эта проверка делается просто:
if ($input =~ m/stop|quit|exit|abort/i) { exit }
Вы можете также проверить, что пользователь кроме ключевого слова больше ничего не вводил. Для этого оператор m надо записать так:
if ($input =~ m/^(stop|quit|exit|abort)$/i) { exit }
Мы предполагаем, что ввод пользователя содержится в переменной $input. Символы " =~ " надо рассматривать как единый символ, это оператор связывания переменной $input с данным оператором m. Этот оператор связывания возвратит число 1, если оператор поиска m найдет в $input текст, соотнесенный с
Символы " / " не принадлежат к \/. Это может порождать частокол из обратных и прямых слэшей внутри #, !, ,, :, % и т.д. Например, оператор
print ':' =~ m:[abc\:def]:;
напечатает единицу. Символы-ограничители лучше выбирать по возможности такими, которые не встречаются в *, +, -, |, (, ), [, ], {, } ", потому что в регулярном выражении они играют особую роль.
Символы-ограничители могут быть парными: это все виды скобок (), <>, [] и {}. Имеются в виду символы ASCII, т.к. существуют угловые скобки, не принадлежащие к 7-битным символам. В этом случае перед
Если в качестве ограничителей выступают слэши " / ", то букву m можно не писать. Здесь еще следует добавить, что если ограничителями выступают вопросительные знаки, то букву m также можно не ставить, но эти ограничители включают довольно экзотический режим поиска, которые относится к "подозрительным" экспериментам и может не войти в будущие версии
Если в качестве целевого текста для оператора поиска или замены выступает переменная $_, то ее можно опустить вместе со связкой
=~: if (/stop|quit|exit|abort/i) { exit }
Буква i после завершителя регулярного выражения называется /StOp/i будет соответствовать целевой строке 'stop', 'sTOp' и т.д.
Понятие буквы зависит от локальных установок среды выполнения программы. В русской Windows к буквам также будут относиться все русские буквы в кодировке Windows. Во французской Windows результаты будут другими. Существуют специальные директивы и операторы установки локали ( use locale и setlocale ), но аргумент setlocale может отличаться для разных операционных систем. Как установить локаль в
Символ " | ", напоминающий операцию " или ", играет в регулярных выражениях роль, схожую с этой логической связкой. Это конструкция выбора ( альтернативы ). Дойдя до нее, система поиска соответствия начинает с текущей позиции целевой строки сопоставлять ей все
Оператор " | " имеет очень низкий приоритет, поэтому, если перед или после конструкции выбора имеется еще что-то, то ее надо заключить в скобки.
Во втором примере символ " ^ " означает начало строки, а символ " $ " - ее конец. Точный смысл этих символов мы обсудим позже. Эти символы также называют
Если бы во втором примере
^stop|quit|exit|abort$
то оно бы означало следующее: либо stop в начале строки, либо слова quit или exit в любом месте строки, либо abort, стоящее в конце строки. А это было бы не то, что нам нужно.
А теперь рассмотрим другие m (Multiline) меняет смысл ^ и $: в зоне его действия ^ соответствует не только началу текста, но также началу каждой логической строки в этом тексте, т.е совпадает в начале текста и после каждого символа новой строки \n, который не стоит в самом конце текста. $ в зоне действия m совпадает не только в самом конце текста, но также и перед каждым символом \n. Но тогда необходимо иметь еще пару
\A совпадает только в самом начале текста.\Z совпадает только в самом конце текста и перед символом \n, который стоит в самом конце текста. (Например, на случай, если к этому тексту не применили функцию chomp ).\z совпадает исключительно в самом конце текста. Еще имеется \b, который соответствует границе слова (word Boundary). Он соответствует позиции, с одной стороны которой находится буква, цифра или знак подчерка, а с другой стороны такого символа нет. \B имеет противоположный смысл: он соответствует позиции внутри слова, т.е. с одной и другой стороны к нему примыкает буква, цифра или знак подчерка. Заметим, что эти
В \n. Но в зоне действия s точка соответствует одному любому символу. Такое различие бывает нужно, чтобы операция поиска не вышла за пределы логической строки.
В последней версии \C, который соответствует ровно одному байту независимо от того, является ли этот байт началом многобайтового символа или нет. Т.к. мы многобайтовые символы не рассматриваем, то можно в начале программы написать директиву
use bytes;
которая заставит \C, даст некоторое ускорение работы
Как быть, если в данной позиции целевой строки могут стоять (ожидаются) разные символы? Например, параметры тега HTML могут заключаться в апострофы, а также двойные кавычки. Здесь конструкцию выбора применять неудобно. Для этого существуют [""] совпадает с апострофом и с двойной кавычкой.
Заметьте, что
Классы имеют свои ] является \]. А символ [ является
Внутри [a-f0-9] - это то же, что [abcdef0123456789], но первая запись короче. Диапазон включает все промежуточные символы, чьи коды расположены между кодами крайних символов. Если вы захотите включить знак минус в
Символ " ^ " внутри класса уже не означает начала строки, ^ ", который стоит в самом начале класса, инвертирует этот класс, и такой инвертированный класс соответствует любому из символов, кроме перечисленных в этом классе.
Некоторые классы так часто используются, что для их обозначения придумали специальные
\d соответствует десятичной цифре: [0-9].\D соответствует одному символу, не являющемуся цифрой: [^0-9].\w соответствует символу, входящему в слово: [a-zA-Z0-9_]. Но вы должны помнить, что этот класс чувствителен к локальной установке и может включать символы букв национального алфавита.\W соответствует любому символу, не входящему в слово: [^a-zA-Z0-9_]. Он тоже чувствителен к локали.\s соответствует одному "пробельному" символу. Пробельными символами считаются:32 ;\t с кодом 9 ;\n с кодом 10 ;\r с кодом 13 ;\f с кодом 12.Таким образом, \s - это класс [ \t\r\n\f].
\S соответствет непробельному символу: [^ \t\r\n\f].
Еще заметим, что если i, то в этот класс неявно включаются соответствующие буквы также другого регистра, чтобы он соответствовал символу без учета регистра букв. Например, класс [a-c] в зоне действия i соответствует символу из диапазонов a-cA-C, а класс [^a] в зоне действия i уже не соответствует символу A.
Для задания символа по его коду можно воспользоваться \xHH, где HH - две шестнадцатеричные цифры кода символа. Например, \x20 - это символ пробела, а \xFF - код буквы "я" в кодировке Windows (это число 255). Шестнадцатеричные цифры можно набирать в любом регистре, а буква x должна быть в нижнем регистре.
Имеется возможность использовать для этого также восьмеричную систему, например, \040 - код пробела и \377 - код буквы "я". После обратной косой должно быть ровно три восьмеричных цифры. Но я не советую пользоваться восьмеричной системой, т.к. это вступает в конфликт с обозначением
Ознакомимся с a{0,4} соответствует нулю, одной, двум, трем и четырем буквам " a ", идущим подряд.
Соответствие нулю каких-то символов означает соответствие пустой подстроке. Если максимальный параметр не ограничен, то его можно опустить: a{1,} соответствует последовательности из одной и более букв " а ". a{3} соответствует ровно трем подряд буквам a, это то же, что и aaa.
В
Некоторые
a* - это нуль или больше символов a: a{0,} ;a+ - это один или больше символов a: a{1,} ;a? - это нуль или один символ a: a{0,1}.bil+ соответствует символам bi, после которых идет одна или больше букв l и далее последовательность . Если вы хотите, чтобы
(bil)+ing соответстсвует строкам biling bilbiling bilbilbiling и т.д.
По умолчанию, алгоритм работы $text имеем текст
<b>Текст выделен жирным шрифтом.</b> Простой текст <b>Это опять жирный</b>
Если применить к этому тексту <b>.+</b>: $text =~ /<b>.+</b>/ то оно будет соответствовать всему этому тексту, а не фрагменту <b>Текст выделен жирным шрифтом.</b>
Аналогично, в
\w*a
примененном к строке
abcabcaaaaa
\w* будет соответствовать подстроке
abcabcaaaa
(без последней буквы a ), а не подстроке
abca
или
abcabca
Имеется способ заставить
a+?
соответствует минимуму из одной и более букв " a ". Если этот
bbbaaaabbb
то такой а, после чего оператор поиска закончит работу, вернув число 1.
В
a*?
a, а это значит, что совпадение будет найдено в любом месте, даже после истинного конца строки! Оператор
print "a" =~ /\za*/;
напечатает 1.
Вот другие примеры
\w?
(abc){3,5}?
Поиск соответствия давал бы мало пользы, если бы нельзя было извлекать из текста интересующие нас фрагменты. Для извлечения фрагмента текста часть $1, сопоставленный второй паре $2 и т.д. до $99.
Разумеется, не обязательно иметь 99 пар скобок, - незадействованные специальные переменные будут иметь неопределенное значение. Обратите внимание, что нумерация начинается не с нуля и что переменная $0 не имеет отношения к
Рассмотрим такой пример: пусть в переменной $text хранится текст для тега a
<a href="http://www.intuit.ru/">Internet-обучение</a>
Нам надо написать a и извлекает из него ссылку. Можно написать так:
$text =~ m#<a href="([^"]+)">[^<]+</a>#; print $1;
Заметьте, что в качестве символов-ограничителей были выбраны решетки, чтобы избежать частокола замаскированных символов /, которые встречаются в
Сначала в
<a href="
который один к одному соответствует своему двойнику в целевой строке $text. Затем в целевой строке стоит ссылка, которую и надо получить. Поэтому мы открываем
[^"]+
означает "любое число символов от 1 и более, которые не содержат кавычек". Поэтому скобки сохранят нам весь текст до следующих кавычек, а это и есть ссылка. Дальше в >, а
[^<]+
соответствует всему до открывающей угловой скобки, затем вновь идет литеральный текст, который соответствует такому же тексту в переменной $text.
Записанное <a будет не один пробел, а больше, или будет стоять перевод строки, то оператор поиска не найдет соответствия и переменная $1 будет иметь неопределенное значение (или значение, которое осталось от предыдущего оператора поиска или замены). Имейте в виду, что $1, …, $99 изменяются только при успешном поиске! Кроме того, надежнее вести поиск без учета регистра символов. С учетом этих требований, получаем такую версию нашей программы:
$text='<a href="http://www.intuit.ru/">Internet-обучение</a>'; $text =~ m#<a\s+href="([^"]+)">[^<]+</a>#i; print $1;
После <a вместо пробела теперь стоит \s+, он берет на себя все пробельные символы, один из которых обязательно должен встретиться по правилам HTML. Кроме того, появился i. Но правила не запрещают иметь пробельные символы перед и после знака равенства, это тоже надо учесть и вставить вокруг него конструкции \s*. Надо также что-то придумать насчет кавычек, ведь на их месте могут быть апострофы или вообще ничего. Модернизированный вариант выглядит так:
$text='<a href="http://www.intuit.ru/">Internet-обучение</a>';
if ($text =~ m#<a\s+href\s*=\s*["']?([^"'> ]+)["']?>[^<]+</a>#i) { print $1 }
Еще мы заключили оператор поиска в условный оператор, чтобы печать была лишь в случае нахождения ссылки, чтобы не получить мусор, оставшийся от предыдущих операторов поиска или замены или предупреждение об использовании неопределенной переменной.
Теперь ["']? возьмет на себя кавычку или апостоф только в случае, если этот символ присутствует. Внутри
Это уже лучше, но в теге a могут быть параметры, например, target=_blank, как быть тогда? Тогда наш оператор поиска закончится неудачей, ведь в target=_blank ничего не будет соответствовать.
Это легко обойти, вставив перед закрывающей скобкой
[^>]*
который поглотит все, что будет стоять до этой скобки.
Это хорошо, но ведь параметры тега a ключевые, а не позиционные, и параметр href не обязан стоять первым. Тег может быть оформлен так:
<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>
В этом случае наш оператор поиска не найдет соответствия. Надо пропускать символы, пока не встретится href. Это можно сделать с помощью конструкции
.*?
и не забыть поставить s, потому что тег может располагаться на нескольких строках (после target="_blank" может быть перевод строки), а
Эта конструкция будет пропускать все символы, пока не встретится подстрока href. Но вообще говоря, так мы можем выскочить за границу тега >, если в теге не встретится href. Чтобы увеличить надежность нашего регулярного выражения, можно вместо этой конструкции поставить другую:
[^>]*?
Теперь s можно не ставить.
Еще я советую использовать директиву
use strict;
чтобы транслятор проверял, все ли переменные определены, и параметр w для выдачи предупреждающих сообщений транслятора.
Если вы запускаете скрипт на Web-сервере из браузера, то вставьте также директиву
use CGI::Carp qw(fatalsToBrowser);
чтобы
Вот законченная программа, которая "железобетонно" выводит ссылку из тега a:
#!/usr/bin/perl -w
use strict;
my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>';
if ($text =~ m#<a\s+[^>]*?href\s*=\s*["']?([^"'> ]+)["']?[^>]*>[^<]+</a>#i) { print $1 }
Если вы будете запускать \r. В редакторе Far это можно сделать по клавишам <Shift>+<F2>. Если вывод скрипта будет направлен веб-серверу и от него браузеру, то перед первым выводом (оператором print ) должна идти команда
print "Content-Type: text/html\n\n";
чтобы веб-сервер знал формат содержимого. Попробуйте менять способ оформления тега, оператор поиска должен будет неизменно находить результат.
В этом примере нас не интересовало, соответствует ли левый ограничитель у ссылки правому, но иногда подобные вещи нужно проверять. Например, кто-то по ошибке слева поставил апостроф, а справа - кавычку, или вообще забыл закрыть строку. Для подобных вещей в \1, для второй - \2 и т.д., для 99-й - \99.
Здесь надо отметить такую интересную деталь: если i, то она соответствует тексту, сохраненному соответствующей парой скобок, без учета регистра. О том, что
Чтобы проверить, стоял ли ограничитель перед ссылкой, а если стоял, то соответствовал ли правый ограничитель левому, левый ограничитель надо захватить в скобки. Тогда ссылка окажется в $2, и оператор print надо исправить:
my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>';
if ($text =~ m#<a\s+[^>]*?href\s*=\s*(["']?)([^"'> ]+)\1[^>]*>[^<]+</a>#i) { print $2 }
Теперь вместо второго ["']? мы вставляем ссылку \1 на найденный текст. Если текст не найден (не было ограничителя), то \1 будет соответствовать пустому месту.
В применении
(["'])?
В чем была бы разница? В первом случае, когда знак вопроса стоит внутри \1 (и $1 тоже) получат неопределенное значение. Если ограничитель есть, то это не повлияет на работу оператора поиска. Но если ссылка не будет чем-то ограничена, поиск потерпит неудачу из-за того, что в \1, которая ничему не будет соответствовать, потому что для нее нет соотнесенного фрагмента текста! Если же знак вопроса будет стоять внутри скобок:
(["']?)
то в отсутствие ограничителей у ссылки эта скобка будет существовать, просто она захватит пустой фрагмент текста. \1 также будет соответствовать пустому фрагменту (переменная $1 получит пустое значение), и все будет работать нормально. Вот такие тонкости иногда встречаются в регулярных выражениях!
Кратко рассмотрим оператор замены s. Он отличается от оператора поиска тем, что за
s/…/…/
Это выражение может включать
Если
s<…>'…'
s(…) {…}
Если ограничителями операнда замены выступают апострофы, то выражение для замены рассматривается как строка, заключенная в апострофы, и интерполяция переменных при замене не происходит.
Оператор s может иметь g (Global). (Впрочем, оператор m также может иметь этот
Как результат, оператор замены возвращает число сделанных замен или пустую строку, если замен не было. Если целевой строкой выступает переменная $_, то ее и связку =~ писать не обязательно. Пример:
$_='aabbaa'; print s/a/c/g."\n".$_;
В результате получим вывод:
4 ccbbcc
Вот пример на использование
$_='aa bb aa';
s/(\w+)(?:\s+\w+){2}/$1 $1/;
print;
Получаем вывод:
aa aa
Куда делась третья группа букв? Она была удалена, т.к. оператор s заменяет всю часть текста, что соответствует
$_='aa bb aa'; s/(\w+)\s+\w+/$1 $1/; print;
Получаем вывод:
aa aa aa
А если в поиск включается что-то, что должно остаться без изменений, то это надо взять в
Оператор замены поддерживает e (Evaluation), которого нет в операторе поиска. В этом случае операнд для замены рассматривается как фрагмент кода eval, а полученный в скалярном контексте результат подставляется вместо найденного фрагмента текста. Это дает большую гибкость при замене текста. Более того, e может повторяться несколько раз, что влечет многократное применение функции eval к результату (столько раз, сколько раз повторен e ). Заметим, что остальные
Рассмотрим такой пример на замену переменных их значениями.
my $a='a'; $_='This is $a'; s/(\$\w+)/$1/; print;
В результате будет напечатано
This is $a
В $a, операнд $1='$a' был интерполирован по правилам строк в кавычках и в результате интерполяции получился текст '$a', который и заменил найденный фрагмент текста '$a', т.е. сам себя.
Теперь к оператору замены добавим e:
my $a='a'; $_='This is $a'; s/(\$\w+)/$1/e; print;
В результате получается тот же вывод:
This is $a
Как это объяснить? Теперь операнд для замены $1='$a' был выполнен как код '$a', которая опять заменила саму себя.
Добавим еще один e:
my $a='a'; $_='This is $a'; s/(\$\w+)/$1/ee; print;
В результате получается текст
This is a
В этом случае после выполнения кода $1 получается строка '$a', которая опять выполняется как код 'a'.
Теперь принцип ясен, мы можем продолжить эту аналогию и написать такую загадочную программу:
my $b='b'; my $a='$b'; $_='This is $a'; s/(\$\w+)/$1/eee; print;
В результате выводится текст
This is b
Но вряд ли кому-либо на практике придется применять e больше двух раз.
Если на компьютере у читателя еще не установлена система программирования
m/…/ и замены s/…/…/. Слово регулярные означает "составленные по правилам". То, что стоит вместо многоточия в операторе m и вместо первого многоточия в операторе s, - это и есть m означает match (соответствие), а буква s означает substitution (замена)
Предположим, в программе проверяется ввод пользователя, чтобы выяснить, хочет ли он завершить программу, введя слова stop, quit, exit или abort. Без регулярных выражений вам пришлось бы использовать ряд сравнений с этими образцами, предварительно преобразовав ввод к нижнему регистру. С оператором m эта проверка делается просто:
if ($input =~ m/stop|quit|exit|abort/i) { exit }
Вы можете также проверить, что пользователь кроме ключевого слова больше ничего не вводил. Для этого оператор m надо записать так:
if ($input =~ m/^(stop|quit|exit|abort)$/i) { exit }
Мы предполагаем, что ввод пользователя содержится в переменной $input. Символы " =~ " надо рассматривать как единый символ, это оператор связывания переменной $input с данным оператором m. Этот оператор связывания возвратит число 1, если оператор поиска m найдет в $input текст, соотнесенный с
Символы " / " не принадлежат к \/. Это может порождать частокол из обратных и прямых слэшей внутри #, !, ,, :, % и т.д. Например, оператор
print ':' =~ m:[abc\:def]:;
напечатает единицу. Символы-ограничители лучше выбирать по возможности такими, которые не встречаются в *, +, -, |, (, ), [, ], {, } ", потому что в регулярном выражении они играют особую роль.
Символы-ограничители могут быть парными: это все виды скобок (), <>, [] и {}. Имеются в виду символы ASCII, т.к. существуют угловые скобки, не принадлежащие к 7-битным символам. В этом случае перед
Если в качестве ограничителей выступают слэши " / ", то букву m можно не писать. Здесь еще следует добавить, что если ограничителями выступают вопросительные знаки, то букву m также можно не ставить, но эти ограничители включают довольно экзотический режим поиска, которые относится к "подозрительным" экспериментам и может не войти в будущие версии
Если в качестве целевого текста для оператора поиска или замены выступает переменная $_, то ее можно опустить вместе со связкой
=~: if (/stop|quit|exit|abort/i) { exit }
Буква i после завершителя регулярного выражения называется /StOp/i будет соответствовать целевой строке 'stop', 'sTOp' и т.д.
Понятие буквы зависит от локальных установок среды выполнения программы. В русской Windows к буквам также будут относиться все русские буквы в кодировке Windows. Во французской Windows результаты будут другими. Существуют специальные директивы и операторы установки локали ( use locale и setlocale ), но аргумент setlocale может отличаться для разных операционных систем. Как установить локаль в
Символ " | ", напоминающий операцию " или ", играет в регулярных выражениях роль, схожую с этой логической связкой. Это конструкция выбора ( альтернативы ). Дойдя до нее, система поиска соответствия начинает с текущей позиции целевой строки сопоставлять ей все
Оператор " | " имеет очень низкий приоритет, поэтому, если перед или после конструкции выбора имеется еще что-то, то ее надо заключить в скобки.
Во втором примере символ " ^ " означает начало строки, а символ " $ " - ее конец. Точный смысл этих символов мы обсудим позже. Эти символы также называют
Если бы во втором примере
^stop|quit|exit|abort$
то оно бы означало следующее: либо stop в начале строки, либо слова quit или exit в любом месте строки, либо abort, стоящее в конце строки. А это было бы не то, что нам нужно.
А теперь рассмотрим другие m (Multiline) меняет смысл ^ и $: в зоне его действия ^ соответствует не только началу текста, но также началу каждой логической строки в этом тексте, т.е совпадает в начале текста и после каждого символа новой строки \n, который не стоит в самом конце текста. $ в зоне действия m совпадает не только в самом конце текста, но также и перед каждым символом \n. Но тогда необходимо иметь еще пару
\A совпадает только в самом начале текста.\Z совпадает только в самом конце текста и перед символом \n, который стоит в самом конце текста. (Например, на случай, если к этому тексту не применили функцию chomp ).\z совпадает исключительно в самом конце текста. Еще имеется \b, который соответствует границе слова (word Boundary). Он соответствует позиции, с одной стороны которой находится буква, цифра или знак подчерка, а с другой стороны такого символа нет. \B имеет противоположный смысл: он соответствует позиции внутри слова, т.е. с одной и другой стороны к нему примыкает буква, цифра или знак подчерка. Заметим, что эти
В \n. Но в зоне действия s точка соответствует одному любому символу. Такое различие бывает нужно, чтобы операция поиска не вышла за пределы логической строки.
В последней версии \C, который соответствует ровно одному байту независимо от того, является ли этот байт началом многобайтового символа или нет. Т.к. мы многобайтовые символы не рассматриваем, то можно в начале программы написать директиву
use bytes;
которая заставит \C, даст некоторое ускорение работы
Как быть, если в данной позиции целевой строки могут стоять (ожидаются) разные символы? Например, параметры тега HTML могут заключаться в апострофы, а также двойные кавычки. Здесь конструкцию выбора применять неудобно. Для этого существуют [""] совпадает с апострофом и с двойной кавычкой.
Заметьте, что
Классы имеют свои ] является \]. А символ [ является
Внутри [a-f0-9] - это то же, что [abcdef0123456789], но первая запись короче. Диапазон включает все промежуточные символы, чьи коды расположены между кодами крайних символов. Если вы захотите включить знак минус в
Символ " ^ " внутри класса уже не означает начала строки, ^ ", который стоит в самом начале класса, инвертирует этот класс, и такой инвертированный класс соответствует любому из символов, кроме перечисленных в этом классе.
Некоторые классы так часто используются, что для их обозначения придумали специальные
\d соответствует десятичной цифре: [0-9].\D соответствует одному символу, не являющемуся цифрой: [^0-9].\w соответствует символу, входящему в слово: [a-zA-Z0-9_]. Но вы должны помнить, что этот класс чувствителен к локальной установке и может включать символы букв национального алфавита.\W соответствует любому символу, не входящему в слово: [^a-zA-Z0-9_]. Он тоже чувствителен к локали.\s соответствует одному "пробельному" символу. Пробельными символами считаются:32 ;\t с кодом 9 ;\n с кодом 10 ;\r с кодом 13 ;\f с кодом 12.Таким образом, \s - это класс [ \t\r\n\f].
\S соответствет непробельному символу: [^ \t\r\n\f].
Еще заметим, что если i, то в этот класс неявно включаются соответствующие буквы также другого регистра, чтобы он соответствовал символу без учета регистра букв. Например, класс [a-c] в зоне действия i соответствует символу из диапазонов a-cA-C, а класс [^a] в зоне действия i уже не соответствует символу A.
Для задания символа по его коду можно воспользоваться \xHH, где HH - две шестнадцатеричные цифры кода символа. Например, \x20 - это символ пробела, а \xFF - код буквы "я" в кодировке Windows (это число 255). Шестнадцатеричные цифры можно набирать в любом регистре, а буква x должна быть в нижнем регистре.
Имеется возможность использовать для этого также восьмеричную систему, например, \040 - код пробела и \377 - код буквы "я". После обратной косой должно быть ровно три восьмеричных цифры. Но я не советую пользоваться восьмеричной системой, т.к. это вступает в конфликт с обозначением
Ознакомимся с a{0,4} соответствует нулю, одной, двум, трем и четырем буквам " a ", идущим подряд.
Соответствие нулю каких-то символов означает соответствие пустой подстроке. Если максимальный параметр не ограничен, то его можно опустить: a{1,} соответствует последовательности из одной и более букв " а ". a{3} соответствует ровно трем подряд буквам a, это то же, что и aaa.
В
Некоторые
a* - это нуль или больше символов a: a{0,} ;a+ - это один или больше символов a: a{1,} ;a? - это нуль или один символ a: a{0,1}.bil+ соответствует символам bi, после которых идет одна или больше букв l и далее последовательность . Если вы хотите, чтобы
(bil)+ing соответстсвует строкам biling bilbiling bilbilbiling и т.д.
По умолчанию, алгоритм работы $text имеем текст
<b>Текст выделен жирным шрифтом.</b> Простой текст <b>Это опять жирный</b>
Если применить к этому тексту <b>.+</b>: $text =~ /<b>.+</b>/ то оно будет соответствовать всему этому тексту, а не фрагменту <b>Текст выделен жирным шрифтом.</b>
Аналогично, в
\w*a
примененном к строке
abcabcaaaaa
\w* будет соответствовать подстроке
abcabcaaaa
(без последней буквы a ), а не подстроке
abca
или
abcabca
Имеется способ заставить
a+?
соответствует минимуму из одной и более букв " a ". Если этот
bbbaaaabbb
то такой а, после чего оператор поиска закончит работу, вернув число 1.
В
a*?
a, а это значит, что совпадение будет найдено в любом месте, даже после истинного конца строки! Оператор
print "a" =~ /\za*/;
напечатает 1.
Вот другие примеры
\w?
(abc){3,5}?
Поиск соответствия давал бы мало пользы, если бы нельзя было извлекать из текста интересующие нас фрагменты. Для извлечения фрагмента текста часть $1, сопоставленный второй паре $2 и т.д. до $99.
Разумеется, не обязательно иметь 99 пар скобок, - незадействованные специальные переменные будут иметь неопределенное значение. Обратите внимание, что нумерация начинается не с нуля и что переменная $0 не имеет отношения к
Рассмотрим такой пример: пусть в переменной $text хранится текст для тега a
<a href="http://www.intuit.ru/">Internet-обучение</a>
Нам надо написать a и извлекает из него ссылку. Можно написать так:
$text =~ m#<a href="([^"]+)">[^<]+</a>#; print $1;
Заметьте, что в качестве символов-ограничителей были выбраны решетки, чтобы избежать частокола замаскированных символов /, которые встречаются в
Сначала в
<a href="
который один к одному соответствует своему двойнику в целевой строке $text. Затем в целевой строке стоит ссылка, которую и надо получить. Поэтому мы открываем
[^"]+
означает "любое число символов от 1 и более, которые не содержат кавычек". Поэтому скобки сохранят нам весь текст до следующих кавычек, а это и есть ссылка. Дальше в >, а
[^<]+
соответствует всему до открывающей угловой скобки, затем вновь идет литеральный текст, который соответствует такому же тексту в переменной $text.
Записанное <a будет не один пробел, а больше, или будет стоять перевод строки, то оператор поиска не найдет соответствия и переменная $1 будет иметь неопределенное значение (или значение, которое осталось от предыдущего оператора поиска или замены). Имейте в виду, что $1, …, $99 изменяются только при успешном поиске! Кроме того, надежнее вести поиск без учета регистра символов. С учетом этих требований, получаем такую версию нашей программы:
$text='<a href="http://www.intuit.ru/">Internet-обучение</a>'; $text =~ m#<a\s+href="([^"]+)">[^<]+</a>#i; print $1;
После <a вместо пробела теперь стоит \s+, он берет на себя все пробельные символы, один из которых обязательно должен встретиться по правилам HTML. Кроме того, появился i. Но правила не запрещают иметь пробельные символы перед и после знака равенства, это тоже надо учесть и вставить вокруг него конструкции \s*. Надо также что-то придумать насчет кавычек, ведь на их месте могут быть апострофы или вообще ничего. Модернизированный вариант выглядит так:
$text='<a href="http://www.intuit.ru/">Internet-обучение</a>';
if ($text =~ m#<a\s+href\s*=\s*["']?([^"'> ]+)["']?>[^<]+</a>#i) { print $1 }
Еще мы заключили оператор поиска в условный оператор, чтобы печать была лишь в случае нахождения ссылки, чтобы не получить мусор, оставшийся от предыдущих операторов поиска или замены или предупреждение об использовании неопределенной переменной.
Теперь ["']? возьмет на себя кавычку или апостоф только в случае, если этот символ присутствует. Внутри
Это уже лучше, но в теге a могут быть параметры, например, target=_blank, как быть тогда? Тогда наш оператор поиска закончится неудачей, ведь в target=_blank ничего не будет соответствовать.
Это легко обойти, вставив перед закрывающей скобкой
[^>]*
который поглотит все, что будет стоять до этой скобки.
Это хорошо, но ведь параметры тега a ключевые, а не позиционные, и параметр href не обязан стоять первым. Тег может быть оформлен так:
<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>
В этом случае наш оператор поиска не найдет соответствия. Надо пропускать символы, пока не встретится href. Это можно сделать с помощью конструкции
.*?
и не забыть поставить s, потому что тег может располагаться на нескольких строках (после target="_blank" может быть перевод строки), а
Эта конструкция будет пропускать все символы, пока не встретится подстрока href. Но вообще говоря, так мы можем выскочить за границу тега >, если в теге не встретится href. Чтобы увеличить надежность нашего регулярного выражения, можно вместо этой конструкции поставить другую:
[^>]*?
Теперь s можно не ставить.
Еще я советую использовать директиву
use strict;
чтобы транслятор проверял, все ли переменные определены, и параметр w для выдачи предупреждающих сообщений транслятора.
Если вы запускаете скрипт на Web-сервере из браузера, то вставьте также директиву
use CGI::Carp qw(fatalsToBrowser);
чтобы
Вот законченная программа, которая "железобетонно" выводит ссылку из тега a:
#!/usr/bin/perl -w
use strict;
my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>';
if ($text =~ m#<a\s+[^>]*?href\s*=\s*["']?([^"'> ]+)["']?[^>]*>[^<]+</a>#i) { print $1 }
Если вы будете запускать \r. В редакторе Far это можно сделать по клавишам <Shift>+<F2>. Если вывод скрипта будет направлен веб-серверу и от него браузеру, то перед первым выводом (оператором print ) должна идти команда
print "Content-Type: text/html\n\n";
чтобы веб-сервер знал формат содержимого. Попробуйте менять способ оформления тега, оператор поиска должен будет неизменно находить результат.
В этом примере нас не интересовало, соответствует ли левый ограничитель у ссылки правому, но иногда подобные вещи нужно проверять. Например, кто-то по ошибке слева поставил апостроф, а справа - кавычку, или вообще забыл закрыть строку. Для подобных вещей в \1, для второй - \2 и т.д., для 99-й - \99.
Здесь надо отметить такую интересную деталь: если i, то она соответствует тексту, сохраненному соответствующей парой скобок, без учета регистра. О том, что
Чтобы проверить, стоял ли ограничитель перед ссылкой, а если стоял, то соответствовал ли правый ограничитель левому, левый ограничитель надо захватить в скобки. Тогда ссылка окажется в $2, и оператор print надо исправить:
my $text='<a target="_blank" href="http://www.intuit.ru/">Internet-обучение</a>';
if ($text =~ m#<a\s+[^>]*?href\s*=\s*(["']?)([^"'> ]+)\1[^>]*>[^<]+</a>#i) { print $2 }
Теперь вместо второго ["']? мы вставляем ссылку \1 на найденный текст. Если текст не найден (не было ограничителя), то \1 будет соответствовать пустому месту.
В применении
(["'])?
В чем была бы разница? В первом случае, когда знак вопроса стоит внутри \1 (и $1 тоже) получат неопределенное значение. Если ограничитель есть, то это не повлияет на работу оператора поиска. Но если ссылка не будет чем-то ограничена, поиск потерпит неудачу из-за того, что в \1, которая ничему не будет соответствовать, потому что для нее нет соотнесенного фрагмента текста! Если же знак вопроса будет стоять внутри скобок:
(["']?)
то в отсутствие ограничителей у ссылки эта скобка будет существовать, просто она захватит пустой фрагмент текста. \1 также будет соответствовать пустому фрагменту (переменная $1 получит пустое значение), и все будет работать нормально. Вот такие тонкости иногда встречаются в регулярных выражениях!
Кратко рассмотрим оператор замены s. Он отличается от оператора поиска тем, что за
s/…/…/
Это выражение может включать
Если
s<…>'…'
s(…) {…}
Если ограничителями операнда замены выступают апострофы, то выражение для замены рассматривается как строка, заключенная в апострофы, и интерполяция переменных при замене не происходит.
Оператор s может иметь g (Global). (Впрочем, оператор m также может иметь этот
Как результат, оператор замены возвращает число сделанных замен или пустую строку, если замен не было. Если целевой строкой выступает переменная $_, то ее и связку =~ писать не обязательно. Пример:
$_='aabbaa'; print s/a/c/g."\n".$_;
В результате получим вывод:
4 ccbbcc
Вот пример на использование
$_='aa bb aa';
s/(\w+)(?:\s+\w+){2}/$1 $1/;
print;
Получаем вывод:
aa aa
Куда делась третья группа букв? Она была удалена, т.к. оператор s заменяет всю часть текста, что соответствует
$_='aa bb aa'; s/(\w+)\s+\w+/$1 $1/; print;
Получаем вывод:
aa aa aa
А если в поиск включается что-то, что должно остаться без изменений, то это надо взять в
Оператор замены поддерживает e (Evaluation), которого нет в операторе поиска. В этом случае операнд для замены рассматривается как фрагмент кода eval, а полученный в скалярном контексте результат подставляется вместо найденного фрагмента текста. Это дает большую гибкость при замене текста. Более того, e может повторяться несколько раз, что влечет многократное применение функции eval к результату (столько раз, сколько раз повторен e ). Заметим, что остальные
Рассмотрим такой пример на замену переменных их значениями.
my $a='a'; $_='This is $a'; s/(\$\w+)/$1/; print;
В результате будет напечатано
This is $a
В $a, операнд $1='$a' был интерполирован по правилам строк в кавычках и в результате интерполяции получился текст '$a', который и заменил найденный фрагмент текста '$a', т.е. сам себя.
Теперь к оператору замены добавим e:
my $a='a'; $_='This is $a'; s/(\$\w+)/$1/e; print;
В результате получается тот же вывод:
This is $a
Как это объяснить? Теперь операнд для замены $1='$a' был выполнен как код '$a', которая опять заменила саму себя.
Добавим еще один e:
my $a='a'; $_='This is $a'; s/(\$\w+)/$1/ee; print;
В результате получается текст
This is a
В этом случае после выполнения кода $1 получается строка '$a', которая опять выполняется как код 'a'.
Теперь принцип ясен, мы можем продолжить эту аналогию и написать такую загадочную программу:
my $b='b'; my $a='$b'; $_='This is $a'; s/(\$\w+)/$1/eee; print;
В результате выводится текст
This is b
Но вряд ли кому-либо на практике придется применять e больше двух раз.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.