Это команда perlretut, которую можно запустить в бесплатном хостинг-провайдере OnWorks, используя одну из наших многочисленных бесплатных онлайн-рабочих станций, таких как Ubuntu Online, Fedora Online, онлайн-эмулятор Windows или онлайн-эмулятор MAC OS.
ПРОГРАММА:
ИМЯ
perlretut - Учебник по регулярным выражениям Perl
ОПИСАНИЕ
На этой странице представлено базовое руководство по пониманию, созданию и использованию обычных
выражения в Perl. Он служит дополнением к справочной странице на регулярных
выражения perlre. Регулярные выражения являются неотъемлемой частью "m //", "s ///", "qr //"
и операторы "split", поэтому этот учебник также пересекается с "Regexp Quote-Like"
Операторы "perlop" и "split" в perlfunc.
Perl широко известен своим превосходным качеством обработки текста, и регулярные выражения - одно из них.
из основных факторов, стоящих за этой славой. Регулярные выражения Perl демонстрируют эффективность и
гибкость, неизвестная большинству других компьютерных языков. Осваивая даже основы
регулярные выражения позволят вам с удивительной легкостью манипулировать текстом.
Что такое регулярное выражение? Регулярное выражение - это просто строка, описывающая
шаблон. В наши дни паттерны широко используются; примеры - шаблоны, набранные в
поисковая система для поиска веб-страниц и шаблонов, используемых для перечисления файлов в каталоге, например,
"ls * .txt" или "dir *. *". В Perl используются шаблоны, описываемые регулярными выражениями.
для поиска строк, извлечения желаемых частей строк, а также для поиска и замены
операций.
Регулярные выражения имеют незаслуженную репутацию абстрактных и трудных для понимания.
понимать. Регулярные выражения создаются с использованием простых понятий, таких как условные выражения.
и циклы, и их не сложнее понять, чем соответствующие условные выражения "если"
и цикл while в самом языке Perl. На самом деле главная проблема в обучении
регулярные выражения просто привыкают к краткой нотации, используемой для выражения этих
концепции.
Это руководство упрощает процесс обучения, обсуждая концепции регулярных выражений, а также
с их обозначениями, по одному и с множеством примеров. Первая часть учебника
продвинется от простейшего поиска слов к базовым концепциям регулярных выражений.
Если вы освоите первую часть, у вас будут все инструменты, необходимые для решения около 98%
твои нужды. Вторая часть руководства предназначена для тех, кто знаком с основами и
жаждет больше электроинструментов. В нем обсуждаются более продвинутые операторы регулярных выражений.
и знакомит с последними передовыми инновациями.
Примечание: для экономии времени «регулярное выражение» часто сокращается до regexp или regex.
Регулярное выражение - более естественное сокращение, чем регулярное выражение, но его труднее произносить. Perl
документация модуля равномерно разделена на регулярное выражение и регулярное выражение; в Perl есть более одного способа
чтобы сократить его. В этом уроке мы будем использовать регулярное выражение.
Новое в v5.22, "use re 'strict'" применяет более строгие правила, чем в противном случае, при компиляции.
шаблоны регулярных выражений. Он может находить вещи, которые, хотя и законны, могут не подходить вам.
предназначена.
часть 1: The основы
Простой слово согласование
Простейшее регулярное выражение - это просто слово или, в более общем смысле, строка символов. Регулярное выражение
состоящий из слова соответствует любой строке, содержащей это слово:
"Hello World" = ~ / World /; # Матчи
Что это за утверждение Perl? «Hello World» - это простая строка в двойных кавычках.
"World" - это регулярное выражение, а "//", заключающее "/ World /", указывает Perl искать
строка для совпадения. Оператор "= ~" связывает строку с совпадением регулярного выражения и
выдает истинное значение, если регулярное выражение соответствует, или ложь, если регулярное выражение не совпадает. В нашем
case, «World» соответствует второму слову в «Hello World», поэтому выражение истинно.
Подобные выражения полезны в условных выражениях:
if ("Hello World" = ~ / World /) {
print "Соответствует \ n";
}
еще {
print "Не совпадает \ n";
}
На эту тему есть полезные вариации. Смысл матча может быть изменен
с помощью оператора "! ~":
if ("Hello World"! ~ / World /) {
print "Не совпадает \ n";
}
еще {
print "Соответствует \ n";
}
Литеральную строку в регулярном выражении можно заменить переменной:
$ приветствие = "Мир";
if ("Hello World" = ~ / $ приветствие /) {
print "Соответствует \ n";
}
еще {
print "Не совпадает \ n";
}
Если вы сопоставляете специальную переменную по умолчанию $ _, часть «$ _ = ~» может быть
опущено:
$ _ = "Привет, мир";
if (/ World /) {
print "Соответствует \ n";
}
еще {
print "Не совпадает \ n";
}
И, наконец, разделители "//" по умолчанию для совпадения можно изменить на произвольные.
разделители, поставив перед ним букву "m":
"Hello World" = ~ m! World !; # совпадений, разделенных знаком "!"
"Hello World" = ~ m {World}; # совпадений, обратите внимание на совпадение "{}"
"/ usr / bin / perl"= ~ m" / perl "; # соответствует после '/ USR / бен',
# '/' становится обычным символом
«/ World /», «m! World!» И «m {World}» представляют одно и то же. Когда, например, цитата
("" ") используется в качестве разделителя, косая черта '/' становится обычным символом и может
можно без проблем использовать в этом регулярном выражении.
Давайте посмотрим, как разные регулярные выражения будут соответствовать "Hello World":
«Привет, мир» = ~ / world /; # не совпадает
"Hello World" = ~ / o W /; # Матчи
«Привет, мир» = ~ / oW /; # не совпадает
"Hello World" = ~ / World /; # не совпадает
Первое регулярное выражение "world" не соответствует, потому что регулярные выражения чувствительны к регистру. Секунда
regexp соответствует, потому что подстрока 'o W' встречается в строке «Hello World». Космос
символ '' обрабатывается как любой другой символ в регулярном выражении и необходим для сопоставления в
Это дело. Отсутствие пробела - причина того, что третье регулярное выражение 'oW' не
соответствие. Четвертое регулярное выражение "World" не соответствует, потому что в конце есть пробел.
регулярное выражение, но не в конце строки. Урок здесь в том, что регулярные выражения должны соответствовать
часть строки точно, для того, чтобы утверждение было правдой.
Если регулярное выражение соответствует более чем в одном месте в строке, Perl всегда будет соответствовать в
самая ранняя возможная точка в строке:
"Hello World" = ~ / o /; # соответствует 'o' в 'Hello'
«Эта шляпа красная» = ~ / hat /; # соответствует 'hat' в 'That'
Что касается сопоставления символов, вам нужно знать еще несколько моментов.
Во-первых, не все символы могут использоваться в матче «как есть». Некоторые персонажи, называемые
метасимволы, зарезервированы для использования в нотации регулярных выражений. Метасимволы
{} [] () ^ $. | * +? \
Значение каждого из них будет объяснено в оставшейся части учебника, но для
теперь важно только знать, что метасимвол можно сопоставить, поставив
обратная косая черта перед ним:
«2 + 2 = 4» = ~ / 2 + 2 /; # не совпадает, + - метасимвол
«2 + 2 = 4» = ~ / 2 \ + 2 /; # совпадений, \ + рассматривается как обычный +
«Интервал равен [0,1)». = ~ /[0,1)./ # - синтаксическая ошибка!
«Интервал равен [0,1)». = ~ /\[0,1\)\./ # совпадений
"#!/ usr / bin / perl"= ~ / #! \/ USR\/ бен\ / perl /; # Матчи
В последнем регулярном выражении косая черта '/' также имеет обратную косую черту, потому что она используется для
ограничить регулярное выражение. Однако это может привести к LTS (синдрому опрокинутой зубочистки), и это
часто более читабельные, чтобы изменить разделители.
"#!/ usr / bin / perl"= ~ м! # \!/ usr / bin / perl!; # легче читать
Символ обратной косой черты '\' сам по себе является метасимволом и требует обратной косой черты:
'C: \ WIN32' = ~ / C: \\ WIN /; # Матчи
Помимо метасимволов, есть некоторые символы ASCII, которые не имеют
печатаемые эквиваленты символов и вместо этого представлены бежать последовательности, общий
примеры: «\ t» для табуляции, «\ n» для новой строки, «\ r» для возврата каретки и «\ a» для
звонок (или оповещение). Если вашу строку лучше рассматривать как последовательность произвольных байтов,
восьмеричная escape-последовательность, например, «\ 033», или шестнадцатеричная escape-последовательность, например, «\ x1B» может
быть более естественным представлением ваших байтов. Вот несколько примеров побегов:
"1000 \ t2000" = ~ m (0 \ t2) # совпадений
"1000 \ n2000" = ~ / 0 \ n20 / # совпадений
"1000 \ t2000" = ~ / \ 000 \ t2 / # не соответствует, "0" ne "\ 000"
"cat" = ~ / \ o {143} \ x61 \ x74 / # соответствует в ASCII, но странным образом
# по буквам кошка
Если вы какое-то время знакомы с Perl, все эти разговоры о escape-последовательностях могут показаться вам знакомыми.
Подобные escape-последовательности используются в строках, заключенных в двойные кавычки, и фактически в регулярных выражениях Perl.
обычно рассматриваются как строки в двойных кавычках. Это означает, что переменные можно использовать в
регулярные выражения. Как и строки в двойных кавычках, значения переменных в
regexp будет заменен до того, как регулярное выражение будет оценено для целей сопоставления. Итак, мы
иметь:
$ foo = 'дом';
'housecat' = ~ / $ foo /; # Матчи
'cathouse' = ~ / cat $ foo /; # Матчи
'housecat' = ~ / $ {foo} cat /; # Матчи
Все идет нормально. Обладая указанными выше знаниями, вы уже можете выполнять поиск с помощью всего лишь
о любом буквальном строковом регулярном выражении, которое только можно придумать. Вот очень декриминализовано подражание
Программа Unix grep:
% cat> simple_grep
#!/ usr / bin / perl
$ regexp = сдвиг;
в то время как (<>) {
напечатать if / $ regexp /;
}
^D
% chmod + x simple_grep
% simple_grep abba / usr / dict / слова
Бэббидж
капуста
капусту
суббота
Соблюдать субботу
Субботится
субботний
ножны
ножны
Эта программа проста для понимания. "#!/ usr / bin / perl"- стандартный способ вызвать
программа на perl из оболочки. "$ regexp = shift;" сохраняет первый аргумент командной строки как
используемое регулярное выражение, оставив остальные аргументы командной строки, которые будут обрабатываться как
файлы. "while (<>)" перебирает все строки во всех файлах. Для каждой строки
"напечатать if / $ regexp /;" печатает строку, если регулярное выражение соответствует строке. В этой строке оба
"print" и "/ $ regexp /" неявно используют переменную по умолчанию $ _.
Со всеми вышеперечисленными регулярными выражениями, если регулярное выражение совпадало в любом месте строки, оно было
считается совпадением. Однако иногда мы хотели бы указать в котором в строке
regexp должен попытаться сопоставить. Для этого мы использовали бы якорь метасимволы "^" и
«$». Якорь «^» означает совпадение в начале строки, а якорь «$» означает
соответствует в конце строки или перед новой строкой в конце строки. Вот как
Они используются:
"экономка" = ~ / хранитель /; # Матчи
"экономка" = ~ / ^ хранитель /; # не совпадает
"экономка" = ~ / хранитель $ /; # Матчи
"экономка \ n" = ~ / хранитель $ /; # Матчи
Второе регулярное выражение не соответствует, потому что "^" ограничивает "хранителя" на соответствие только в
начало строки, но у «экономки» есть хранитель, начинающийся в середине. Третий
regexp действительно совпадает, поскольку "$" ограничивает "хранителя", чтобы он соответствовал только в конце
строка.
Когда одновременно используются "^" и "$", регулярное выражение должно соответствовать обоим
начало и конец строки, т.е. регулярное выражение соответствует всей строке. Рассмотреть возможность
"хранитель" = ~ / ^ держать $ /; # не совпадает
"хранитель" = ~ / ^ хранитель $ /; # Матчи
"" = ~ / ^ $ /; # ^ $ соответствует пустой строке
Первое регулярное выражение не соответствует, потому что в строке есть нечто большее, чем «сохранить». Поскольку
второе регулярное выражение - это именно та строка, которой она соответствует. Использование "^" и "$" в регулярном выражении
приводит к совпадению всей строки, поэтому вы можете полностью контролировать, какие строки
совпадают, а какие нет. Предположим, вы ищете парня по имени Берт, в цепочке
сам:
"dogbert" = ~ / bert /; # совпадений, но не то, что вы хотите
«дилберт» = ~ / ^ bert /; # не совпадает, но ..
"bertram" = ~ / ^ bert /; # совпадений, значит, все еще недостаточно
"bertram" = ~ / ^ bert $ /; # не совпадает, хорошо
"dilbert" = ~ / ^ bert $ /; # не совпадает, хорошо
"bert" = ~ / ^ bert $ /; # совпадений, отлично
Конечно, в случае буквальной строки можно так же легко использовать строку
сравнение "$ string eq 'bert'", и это было бы более эффективно. Регулярное выражение "^ ... $"
действительно становится полезным, когда мы добавляем более мощные инструменты регулярного выражения ниже.
. персонаж классов
Хотя с регулярными выражениями буквальных строк, приведенными выше, уже можно сделать довольно много, мы только
коснулся поверхности технологии регулярных выражений. В этом и последующих разделах
мы представим концепции регулярных выражений (и связанные с ними обозначения метасимволов), которые позволят
регулярное выражение для представления не только одиночной символьной последовательности, но и все класс из них.
Одна из таких концепций - концепция персонаж класс. Класс символов допускает набор возможных
символы, а не просто один символ, чтобы соответствовать в определенной точке в
регулярное выражение. Вы можете определить свои собственные классы персонажей. Они обозначены скобками
«[...]», с набором символов, которые могут быть сопоставлены внутри. Вот некоторые
Примеры:
/Кот/; # соответствует 'cat'
/ [bcr] at /; # соответствует 'летучая мышь', 'кошка' или 'крыса'
/ item [0123456789] /; # соответствует 'item0' или ... или 'item9'
"abc" = ~ / [кабина] /; # соответствует 'a'
В последнем операторе, даже если 'c' является первым символом в классе, 'a' соответствует
потому что позиция первого символа в строке - это самая ранняя точка, в которой
регулярное выражение может соответствовать.
/ [yY] [eE] [sS] /; # совпадение с "да" без учета регистра
# 'yes', 'Yes', 'YES' и т. д.
Это регулярное выражение отображает общую задачу: выполнить сопоставление без учета регистра. Perl предоставляет способ
чтобы избежать всех этих скобок, просто добавив «i» в конец совпадения. потом
"/ [yY] [eE] [sS] /;" можно переписать как «/ yes / i;». Буква i означает регистронезависимость, а
это пример изменение операции сопоставления. Позже мы познакомимся с другими модификаторами
в учебнике.
В разделе выше мы видели, что были обычные персонажи, которые представляли
сами по себе и специальные символы, для обозначения которых требуется обратная косая черта "\".
То же верно и для класса символов, но наборы обычных и специальных символов
внутри символьного класса отличаются от символьных классов. Специальный
символы для класса символов: «-] \ ^ $» (и разделитель шаблона, какой бы он ни был).
«]» является особенным, поскольку обозначает конец класса символов. "$" особенный, потому что он
обозначает скалярную переменную. "\" особенный, потому что он используется в escape-последовательностях, просто
как указано выше. Вот как обрабатываются специальные символы "] $ \":
/ [\] c] def /; # соответствует '] def' или 'cdef'
$ x = 'bcr';
/ [$ x] в /; # соответствует 'летучая мышь', 'кошка' или 'крыса'
/ [\ $ x] в /; # соответствует '$ at' или 'xat'
/ [\\ $ x] в /; # соответствует '\ at', 'bat,' cat 'или' rat '
Последние два немного сложны. В "[\ $ x]" обратная косая черта защищает знак доллара, поэтому
класс символов состоит из двух членов «$» и «x». В "[\\ $ x]" обратная косая черта защищена,
поэтому $ x рассматривается как переменная и подставляется в двойные кавычки.
Специальный символ '-' действует как оператор диапазона в классах символов, так что
непрерывный набор символов можно записать как диапазон. С диапазонами громоздкий
«[0123456789]» и «[abc ... xyz]» становятся стройными «[0-9]» и «[az]». Некоторые примеры
/ item [0-9] /; # соответствует 'item0' или ... или 'item9'
/ [0-9bx-z] aa /; # соответствует '0aa', ..., '9aa',
# 'baa', 'xaa', 'yaa' или 'zaa'
/ [0-9a-fA-F] /; # соответствует шестнадцатеричной цифре
/ [0-9a-zA-Z _] /; # соответствует символу "слова",
# как в имени переменной Perl
Если '-' является первым или последним символом в классе символов, он рассматривается как обычный
персонаж; «[-ab]», «[ab-]» и «[a \ -b]» эквивалентны.
Специальный символ «^» в первой позиции класса символов обозначает инвертированный
персонаж класс, который соответствует любому символу, кроме указанных в скобках. Оба и
«[^ ...]» должно соответствовать символу, иначе совпадение не удастся. потом
/ [^ a] at /; # не соответствует 'aat' или 'at', но соответствует
# все остальные 'bat', 'cat,' 0at ','% at 'и т. д.
/ [^ 0-9] /; # соответствует нечисловому символу
/ [a ^] at /; # соответствует 'aat' или '^ at'; здесь '^' обычное
Теперь даже "[0-9]" может быть затруднительным при записи несколько раз, поэтому в интересах экономии
нажатия клавиш и делая регулярные выражения более удобочитаемыми, Perl имеет несколько сокращений для общих
классы персонажей, как показано ниже. С момента появления Unicode, если только "// a"
действует модификатор, эти классы символов соответствуют более чем нескольким символам в
диапазон ASCII.
· \ D соответствует цифре, не только [0-9], но и цифрам из нелатинских шрифтов.
· \ S соответствует пробельному символу, набору [\ \ t \ r \ n \ f] и другим
· \ W соответствует символу слова (буквенно-цифровому или _), а не только [0-9a-zA-Z_], но и цифрам
и персонажи из нелатинских шрифтов
· \ D - отрицательный \ d; он представляет любой другой символ, кроме цифры, или [^ \ d]
· \ S - отрицательный \ s; он представляет собой любой непробельный символ [^ \ s]
· \ W - отрицательный \ w; он представляет собой любой символ, не являющийся словом [^ \ w]
· Период '.' соответствует любому символу, кроме "\ n" (если не действует модификатор "// s",
как объяснено ниже).
· \ N, как и точка, соответствует любому символу, кроме "\ n", но делает это независимо от
действует ли модификатор "// s".
Модификатор «// a», доступный начиная с Perl 5.14, используется для ограничения совпадений
\ d, \ s и \ w только для тех, которые находятся в диапазоне ASCII. Полезно держать вашу программу от
бесполезное использование полного Unicode (и связанных с ним соображений безопасности)
когда все, что вам нужно, это обработать текст, похожий на английский. ("A" может быть удвоено, "// aa", чтобы
предоставляют еще больше ограничений, предотвращая нечувствительное к регистру сопоставление ASCII с не-
Символы ASCII; в противном случае Unicode «Знак Кельвина» без учета регистра соответствовал бы «k» или «K».)
Сокращения "\ d \ s \ w \ D \ S \ W" могут использоваться как внутри, так и вне скобок.
классы персонажей. Вот некоторые из них:
/ \ d \ d: \ d \ d: \ d \ d /; # соответствует формату времени чч: мм: сс
/ [\ d \ s] /; # соответствует любой цифре или пробельному символу
/ \ w \ W \ w /; # соответствует слову char, за которым следует
# символ без слова, за которым следует слово char
/..rt/; # соответствует любым двум символам, за которыми следует 'rt'
/конец\./; # соответствует 'end.'
/конец[.]/; # то же самое, соответствует 'end.'
Поскольку точка является метасимволом, ее необходимо экранировать, чтобы она соответствовала обычным
период. Так как, например, "\ d" и "\ w" представляют собой наборы символов, неверно
думайте о «[^ \ d \ w]» как о «[\ D \ W]»; фактически «[^ \ d \ w]» - это то же самое, что «[^ \ w]», что является
то же, что и "[\ W]". Подумайте о законах ДеМоргана.
На самом деле, точка и аббревиатуры "\ d \ s \ w \ D \ S \ W" сами по себе являются типами
классы символов, поэтому те, которые заключены в квадратные скобки, представляют собой только один тип символов
класс. Когда нам нужно провести различие, мы называем их "заключенный в квадратные скобки"
классы ".
Якорь, полезный в базовых регулярных выражениях, - это слово якорь "\ b". Это соответствует границе
между символом слова и символом, не являющимся словом "\ w \ W" или "\ W \ w":
$ x = "Домашняя кошка связывает дом и кошку";
$ x = ~ / cat /; # соответствует cat в 'housecat'
$ х = ~ / \ bcat /; # соответствует cat в 'catenates'
$ x = ~ / кошка \ b /; # соответствует cat в 'housecat'
$ х = ~ / \ bcat \ b /; # соответствует 'cat' в конце строки
Обратите внимание, что в последнем примере конец строки считается границей слова.
Для обработки естественного языка (чтобы, например, в слова включались апострофы),
используйте вместо "\ b {wb}"
"не" = ~ /. +? \ b {wb} / х; # соответствует всей строке
Вы можете спросить, почему '.' соответствует всему, кроме "\ n" - почему не каждому символу? Причина
заключается в том, что часто сравниваются строки и хотелось бы игнорировать новую строку
символы. Например, хотя строка "\ n" представляет одну строку, мы хотели бы
думайте об этом как о пустом. потом
"" = ~ / ^ $ /; # Матчи
"\ n" = ~ / ^ $ /; # совпадений, $ якоря перед "\ n"
"" = ~ /./; # не совпадает; ему нужен чар
"" = ~ /^.$/; # не совпадает; ему нужен чар
"\ n" = ~ /^.$/; # не совпадает; ему нужен символ, отличный от "\ n"
"а" = ~ /^.$/; # Матчи
"а \ п" = ~ /^.$/; # совпадений, $ якоря перед "\ n"
Такое поведение удобно, потому что мы обычно хотим игнорировать символы новой строки при подсчете и
совпадать символы в строке. Однако иногда мы хотим отслеживать новые строки. Мы
может даже понадобиться "^" и "$" для привязки к началу и концу строк внутри строки,
а не только начало и конец строки. Perl позволяет нам выбирать между
игнорирование и уделение внимания символам новой строки с помощью модификаторов «// s» и «// m». "// с"
и "// m" обозначают однострочное и многострочное, и они определяют, должна ли строка
рассматриваться как одна непрерывная строка или как набор строк. Два модификатора влияют на два
аспекты того, как интерпретируется регулярное выражение: 1) как '.' класс символов определен, и
2) где якоря «^» и «$» могут совпадать. Вот четыре возможных
комбинации:
· Без модификаторов (//): поведение по умолчанию. '.' соответствует любому символу, кроме "\ n". "^"
соответствует только в начале строки, а "$" соответствует только в конце или перед
перевод строки в конце.
· Модификатор s (// s): рассматривать строку как одну длинную строку. '.' соответствует любому символу, даже
"\ п". «^» соответствует только началу строки, а «$» соответствует только ее концу.
или перед новой строкой в конце.
· Модификатор m (// m): рассматривать строку как набор из нескольких строк. '.' соответствует любому персонажу
кроме "\ n". «^» и «$» могут совпадать в начале или в конце любое линия в пределах
строка.
· Оба модификатора s и m (// sm): рассматривать строку как одну длинную строку, но обнаруживать несколько
линий. '.' соответствует любому символу, даже "\ n". Однако "^" и "$" могут соответствовать
в начале или в конце любое строка внутри строки.
Вот примеры «// s» и «// m» в действии:
$ x = "Жила-была девушка \ nКоторая программировала на Perl \ n";
$ x = ~ / ^ Кто /; # не соответствует, "Кто" не в начале строки
$ x = ~ / ^ Кто / с; # не соответствует, "Кто" не в начале строки
$ x = ~ / ^ Кто / м; # совпадений, "Кто" в начале второй строки
$ x = ~ / ^ Кто / см; # совпадений, "Кто" в начале второй строки
$ x = ~ /girl.Who/; # не соответствует, "." не соответствует "\ n"
$ x = ~ /girl.Who/s; # Матчи, "." соответствует "\ n"
$ x = ~ / девушка.Кто / м; # не соответствует, "." не соответствует "\ n"
$ x = ~ / девушка.Кто/см; # Матчи, "." соответствует "\ n"
В большинстве случаев поведение по умолчанию - это то, что нужно, но "// s" и "// m" используются
иногда очень полезно. Если используется "// m", начало строки все еще может быть
совпадает с "\ A", и конец строки все еще может быть сопоставлен с якорем "\ Z"
(соответствует как концу, так и новой строке, например «$») и «\ z» (соответствует только концу):
$ x = ~ / ^ Кто / м; # совпадений, "Кто" в начале второй строки
$ х = ~ / \ AWho / м; # не совпадает, "Кто" не находится в начале строки
$ x = ~ / девушка $ / м; # совпадений, "девушка" в конце первой строки
$ x = ~ / девушка \ Z / m; # не совпадает, "девушка" не в конце строки
$ х = ~ / Perl \ Z / m; # совпадений, "Perl" стоит на новой строке перед концом
$ х = ~ / Perl \ z / m; # не соответствует, "Perl" не находится в конце строки
Теперь мы знаем, как делать выбор среди классов символов в регулярном выражении. Что о
выбор между словами или символьными строками? Такой выбор описан в следующем разделе.
Согласование этой or которая
Иногда нам нужно, чтобы наше регулярное выражение могло соответствовать различным возможным словам или
строки символов. Это достигается с помощью чередование метасимвол "|". К
совпадение "собака" или "кошка", мы формируем регулярное выражение "собака | кошка". Как и раньше, Perl попытается сопоставить
regexp в самом начале строки. В каждой позиции символа Perl
сначала попытается сопоставить первую альтернативу "собака". Если "собака" не совпадает, Perl будет
затем попробуйте следующий вариант - «кот». Если «кот» тоже не совпадает, то совпадение не выполняется.
и Perl переходит на следующую позицию в строке. Некоторые примеры:
«кошки и собаки» = ~ / кошка | собака | птица /; # соответствует "cat"
«кошки и собаки» = ~ / собака | кошка | птица /; # соответствует "cat"
Несмотря на то, что «dog» является первой альтернативой во втором регулярном выражении, «cat» может соответствовать
ранее в строке.
"кошки" = ~ / c | ca | cat | cats /; # соответствует "c"
"кошки" = ~ / cats | cat | ca | c /; # совпадений "коты"
Здесь все альтернативы совпадают в первой строковой позиции, поэтому первая альтернатива -
тот, который соответствует. Если одни из альтернатив являются усечением других, поместите
сначала самые длинные, чтобы дать им шанс сопоставить.
"cab" = ~ / a | b | c / # соответствует "c"
# / a | b | c / == / [abc] /
Последний пример указывает на то, что классы символов подобны чередованиям символов.
В данной позиции символа первая альтернатива, которая позволяет регулярному выражению соответствовать
успешно будет тот, который соответствует.
группирование вещи и иерархическая согласование
Чередование позволяет регулярному выражению выбирать среди альтернатив, но само по себе
неудовлетворительно. Причина в том, что каждая альтернатива представляет собой целое регулярное выражение, но иногда мы хотим
альтернативы только части регулярного выражения. Например, предположим, что мы хотим найти
домашние кошки или домработницы. Регулярное выражение «housecat | housekeeper» отвечает всем требованиям, но является
неэффективно, потому что нам приходилось набирать «дом» дважды. Было бы неплохо, если бы части
regexp должно быть постоянным, как «дом», а в некоторых частях есть альтернативы, например «кот | хранитель».
The группировка метасимволы "()" решают эту проблему. Группировка позволяет частям регулярного выражения
рассматриваться как единое целое. Части регулярного выражения сгруппированы, заключив их в
скобки. Таким образом, мы могли решить «housecat | housekeeper», сформировав регулярное выражение как
"дом (кот | хранитель)". Регулярное выражение «дом (кошка | хранитель)» означает совпадение «дом», за которым следует
либо «кот», либо «хранитель». Еще несколько примеров
/ (a | b) b /; # соответствует 'ab' или 'bb'
/ (ac | b) b /; # соответствует 'acb' или 'bb'
/ (^ a | b) c /; # соответствует 'ac' в начале строки или 'bc' в любом месте
/ (a | [bc]) d /; # соответствует 'ad', 'bd' или 'cd'
/ дом (кот |) /; # соответствует либо 'housecat', либо 'house'
/ house (cat (s |) |) /; # соответствует либо "домашние кошки", либо "домашние кошки", либо
# 'дом'. Группы заметок могут быть вложенными.
/ (19 | 20 |) \ d \ d /; # соответствовать годам 19xx, 20xx или проблеме 2 года, xx
«20» = ~ / (19 | 20 |) \ d \ d /; # соответствует нулевой альтернативе '() \ d \ d',
# потому что '20 \ d \ d 'не может соответствовать
Чередования ведут себя в группах так же, как и вне их: в заданной позиции строки
берется крайняя левая альтернатива, которая позволяет регулярному выражению соответствовать. Итак, в последнем примере на
первая позиция строки, "20" соответствует второй альтернативе, но ничего не осталось
до совпадения следующих двух цифр "\ d \ d". Итак, Perl переходит к следующей альтернативе, которая
- это нулевая альтернатива, и это работает, поскольку «20» - это две цифры.
Процесс опробования одной альтернативы, проверки ее соответствия и перехода к следующему
альтернатива, возвращаясь к строке, из которой была испробована предыдущая альтернатива,
если это не так, называется возвраты. Термин «возврат» происходит от идеи, что
сопоставление регулярного выражения похоже на прогулку по лесу. Успешное сопоставление регулярного выражения похоже на
прибытие в пункт назначения. Есть много возможных следов, по одному на каждую строку
позиции, и каждая из них проверяется по порядку, слева направо. С каждой тропы может быть
много путей, некоторые из которых приведут вас туда, а некоторые - тупиковые. Когда вы идете
по тропе и зайдя в тупик, придется вернуться по тропе к более раннему
указать, чтобы попробовать другой маршрут. Если вы попадаете в пункт назначения, вы немедленно останавливаетесь и забываете
о том, чтобы попробовать все остальные маршруты. Вы настойчивы, и только если вы испробовали все
следы со всех концов тропы и не прибыли в пункт назначения, вы объявляете
отказ. Чтобы быть конкретным, вот пошаговый анализ того, что Perl делает, когда пытается
чтобы соответствовать регулярному выражению
«abcde» = ~ / (abd | abc) (df | d | de) /;
0 Начните с первой буквы в строке «а».
1 Попробуйте первый вариант в первой группе «abd».
2 Сопоставьте "a", а затем "b". Все идет нормально.
3 'd' в регулярном выражении не соответствует 'c' в строке - тупик. Так что вернись два
символов и выберите вторую альтернативу в первой группе «abc».
4 Сопоставьте «a», затем «b», а затем «c». Мы в ударе и удовлетворили
первая группа. Установите $ 1 на "abc".
5 Перейдите ко второй группе и выберите первую альтернативу «df».
6 Совместите букву "d".
7 'f' в регулярном выражении не соответствует 'e' в строке, так что тупик. Вернуться назад
и выберите вторую альтернативу во второй группе 'd'.
8 'd' совпадений. Вторая группировка удовлетворена, поэтому установите $ 2 на 'd'.
9 Мы подошли к концу регулярного выражения, так что все готово! Мы сопоставили "abcd" из
строка «abcde».
В связи с этим анализом следует отметить несколько моментов. Во-первых, третья альтернатива в
вторая группа 'de' также разрешает совпадение, но мы остановились, прежде чем дошли до него - при заданном
позиция символа, крайний левый выигрывает. Во-вторых, мы смогли найти совпадение на первом
позиция символа в строке 'a'. Если на первой позиции не было совпадений,
Perl переместится на позицию второго символа «b» и снова попытается найти совпадение.
Только когда все возможные пути на всех возможных позициях персонажа исчерпаны,
Perl сдаётся и объявляет: «$ string = ~ / (abd | abc) (df | d | de) /;» быть ложным.
Даже после всей этой работы сопоставление регулярных выражений происходит на удивление быстро. Чтобы ускорить процесс,
Perl компилирует регулярное выражение в компактную последовательность кодов операций, которая часто помещается в
кэш процессора. Когда код выполняется, эти коды операций могут работать на полной скорости.
и ищите очень быстро.
экстрагирование спички
Метасимволы группировки "()" также выполняют другую совершенно иную функцию: они
разрешить извлечение совпадающих частей строки. Это очень полезно найти
что совпало и для обработки текста в целом. Для каждой группировки часть, которая
совпадение внутри переходит в специальные переменные $ 1, $ 2 и т. д. Их можно использовать так же, как
обычные переменные:
# извлечь часы, минуты, секунды
if ($ time = ~ / (\ d \ d): (\ d \ d): (\ d \ d) /) {# соответствует формату чч: мм: сс
$ часов = 1 $;
$ минут = 2 доллара;
$ секунды = 3 доллара США;
}
Теперь мы знаем, что в скалярном контексте "$ time = ~ / (\ d \ d): (\ d \ d): (\ d \ d) /" возвращает истину или
ложное значение. Однако в контексте списка он возвращает список совпадающих значений.
"(1 доллар, 2 доллара, 3 доллара)". Таким образом, мы могли бы написать код более компактно, как
# извлечь часы, минуты, секунды
($ часы, $ минуты, $ секунды) = ($ time = ~ / (\ d \ d): (\ d \ d): (\ d \ d) /);
Если группы в регулярном выражении вложены, $ 1 получает группу с крайним левым открытием.
скобка, $ 2 следующая открывающая скобка и т. д. Вот регулярное выражение с вложенными группами:
/ (ab (cd | ef) ((gi) | j)) /;
1 2 34
Если это регулярное выражение совпадает, $ 1 содержит строку, начинающуюся с 'ab', $ 2 либо имеет значение 'cd'
или ef, 3 доллара равняется либо gi, либо j, а 4 доллара либо равно gi, как и 3 доллара, либо
остается неопределенным.
Для удобства Perl устанавливает $ + в строку, содержащую самые высокие номера $ 1, $ 2, ..., что
присвоено (и, в некотором роде, $ ^ N значению $ 1, $ 2, ... совсем недавно
назначенный; то есть $ 1, $ 2, ... связанные с самой правой закрывающей круглой скобкой, используемой в
матч).
Обратные ссылки
С соответствующими переменными $ 1, $ 2, ... тесно связаны обратные ссылки "\ g1",
"\ g2", ... Обратные ссылки - это просто совпадающие переменные, которые можно использовать внутри регулярное выражение.
Это действительно приятная функция; то, что соответствует позже в регулярном выражении, зависит от того, что
совпало ранее в регулярном выражении. Предположим, мы хотим найти в тексте удвоенные слова,
как "the". Следующее регулярное выражение находит все трехбуквенные двойники с пробелом между ними:
/ \ b (\ w \ w \ w) \ s \ g1 \ b /;
Группировка присваивает значение \ g1, так что одна и та же трехбуквенная последовательность используется для обоих
частей.
Аналогичная задача - найти слова, состоящие из двух одинаковых частей:
% simple_grep '^ (\ w \ w \ w \ w | \ w \ w \ w | \ w \ w | \ w) \ g1 $' / usr / dict / слова
авитаминоз
гадостей
кокос
мама
Я бормочу
папа
Регулярное выражение имеет единственную группировку, которая учитывает четырехбуквенные комбинации, затем трехбуквенные.
комбинации и т. д. и использует "\ g1" для поиска повтора. Хотя $ 1 и "\ g1" представляют
то же самое, следует позаботиться о том, чтобы использовать только совпадающие переменные $ 1, $ 2, ... внешнюю a
только регулярное выражение и обратные ссылки "\ g1", "\ g2", ... внутри регулярное выражение; невыполнение этого может привести к
неожиданные и неудовлетворительные результаты.
Относительный обратные ссылки
Подсчет открывающих скобок для получения правильного числа для обратной ссылки является ошибкой -
склонен, как только существует более одной группы захвата. Более удобная техника
стал доступен с Perl 5.10: относительные обратные ссылки. Чтобы сразу обратиться к
предыдущая группа захвата теперь может писать "\ g {-1}", следующая, но последняя доступна через
"\ g {-2}" и так далее.
Еще одна веская причина помимо удобочитаемости и ремонтопригодности для использования относительной
обратные ссылки проиллюстрированы следующим примером, где простой шаблон для
используются соответствующие специфические строки:
$ a99a = '([az]) (\ d) \ g2 \ g1'; # соответствует a11a, g22g, x33x и т. д.
Теперь, когда у нас есть этот шаблон, хранящийся в виде удобной строки, у нас может возникнуть соблазн использовать его как
часть какого-то другого паттерна:
$ line = "код = e99e";
if ($ line = ~ / ^ (\ w +) = $ a99a $ /) {# неожиданное поведение!
print "Действителен $ 1 \ n";
} Еще {
напечатать "плохая строка: '$ line' \ n";
}
Но это не совпадает, по крайней мере, не так, как можно было бы ожидать. Только после вставки
интерполировал $ a99a и, глядя на полученный полный текст регулярного выражения, очевидно, что
обратные ссылки дали обратный эффект. Подвыражение "(\ w +)" выхватило номер 1 и
понизил группы в $ a99a на один ранг. Этого можно избежать, используя относительную
обратные ссылки:
$ a99a = '([az]) (\ d) \ g {-1} \ g {-2}'; # безопасно для интерполяции
Названный обратные ссылки
Perl 5.10 также представил именованные группы захвата и именованные обратные ссылки. Прикрепить имя
группе захвата вы пишете либо "(? ...) "или" (? 'name' ...) ".
обратная ссылка может быть записана как "\ g {name}". Допускается прикрепление одинаковых
имя для более чем одной группы, но тогда только крайний левый из одноименного набора может быть
упоминается. Вне шаблона именованная группа захвата доступна через "% +"
хэш.
Предполагая, что мы должны сопоставить календарные даты, которые могут быть указаны в одной из трех
форматы гггг-мм-дд, мм / дд / гггг или дд.мм.гггг, мы можем написать три подходящих шаблона, где
мы используем 'd', 'm' и 'y' соответственно как имена групп, захватывающих соответствующие
компоненты финика. Операция сопоставления сочетает в себе три шаблона как альтернативы:
$ fmt1 = '(? \ d \ d \ d \ d) - (? \ d \ d) - (? \ d \ d) ';
$ fmt2 = '(? \ d \ d) / (? \ d \ d) / (? \ д \ д \ д \ д) ';
$ fmt3 = '(? \ d \ d) \. (? \ d \ d) \. (? \ д \ д \ д \ д) ';
для моего $ d qw (2006-10-21 15.01.2007 10) {
if ($ d = ~ m {$ fmt1 | $ fmt2 | $ fmt3}) {
напечатайте "день = $ + {d} месяц = $ + {m} год = $ + {y} \ n";
}
}
Если какая-либо из альтернатив совпадает, хэш "% +" обязательно должен содержать три пары "ключ-значение".
пар.
Альтернатива захватить группы нумерация
Еще одна техника нумерации групп захвата (также начиная с Perl 5.10) связана с
проблема ссылки на группы внутри набора альтернатив. Рассмотрим шаблон для
соответствие времени суток, в гражданском или военном стиле:
if ($ time = ~ / (\ d \ d | \ d): (\ d \ d) | (\ d \ d) (\ d \ d) /) {
# процесс час и минута
}
Для обработки результатов требуется дополнительный оператор if, чтобы определить, соответствуют ли значения $ 1 и $ 2.
или 3 и 4 доллара содержат вкусности. Было бы проще, если бы мы могли использовать номера групп 1 и 2.
во второй альтернативе, и это именно то, что заключенная в скобки конструкция
"(? | ...)", установленная вокруг альтернативы достигает. Вот расширенная версия предыдущего
шаблон:
если ($ time = ~ / (? | (\ d \ d | \ d): (\ d \ d) | (\ d \ d) (\ d \ d)) \ s + ([AZ] [AZ] [ AZ]) /) {
напечатайте "час = $ 1 минута = $ 2 зона = $ 3 \ n";
}
В группе альтернативной нумерации номера групп начинаются с одной и той же позиции для каждого
альтернатива. После группы нумерация продолжается на единицу, превышающую достигнутый максимум.
по всем альтернативам.
Позиция информация
В дополнение к тому, что было сопоставлено, Perl также предоставляет позиции того, что было сопоставлено как
содержимое массивов «@ -» и «@ +». "$ - [0]" - позиция начала всего
match, а $ + [0] - позиция конца. Точно так же «$ - [n]» - это позиция
начало совпадения $ n, а $ + [n] - позиция конца. Если $ n не определено, то и
«$ - [n]» и $ + [n]. Тогда этот код
$ x = "Ммм ... пончик, подумал Гомер";
$ x = ~ /^(Mmm|Yech)\.\.\.(donut|peas)/; # Матчи
foreach $ exp (1 .. $ # -) {
print «Соответствует $ exp: '$ {$ exp}' в позиции ($ - [$ exp], $ + [$ exp]) \ n»;
}
печать
Матч 1: «Ммм» в позиции (0,3)
Матч 2: "пончик" в позиции (6,11)
Даже если в регулярном выражении нет группировок, все равно можно узнать, что именно
соответствует в строке. Если вы их используете, Perl установит "$` "в части строки перед
совпадение, установит $ & как часть совпавшей строки и установит "$ '" как
часть строки после совпадения. Пример:
$ x = "кот поймал мышь";
$ x = ~ / cat /; # $ `= 'the', $ & = 'cat', $ '=' поймал мышь '
$ x = ~ / the /; # $ `= '', $ & = 'the', $ '=' кошка поймала мышь '
Во втором совпадении "$` "равно", потому что регулярное выражение соответствует первому символу.
положение в строке и остановлено; он никогда не видел второго «своего».
Если ваш код должен работать в версиях Perl до 5.20, стоит отметить, что
использование "$` "и" $ '"немного замедляет сопоставление регулярных выражений, в то время как $ & замедляет его до
в меньшей степени, потому что, если они используются в одном регулярном выражении в программе, они генерируются для
ВСЕ регулярные выражения в программе. Итак, если целью вашего приложения является чистая производительность, они
необходимо избегать. Если вам нужно извлечь соответствующие подстроки, используйте «@ -» и «@ +».
вместо:
$ `то же самое, что и substr ($ x, 0, $ - [0])
$ & совпадает с substr ($ x, $ - [0], $ + [0] - $ - [0])
$ 'то же самое, что и substr ($ x, $ + [0])
Начиная с Perl 5.10, переменные «$ {^ PREMATCH}», «$ {^ MATCH}» и «$ {^ POSTMATCH}» могут быть
использовал. Они устанавливаются, только если присутствует модификатор «/ p». Следовательно, они не
оштрафовать остальную часть программы. В Perl 5.20 "$ {^ PREMATCH}", "$ {^ MATCH}" и
"$ {^ POSTMATCH}" доступны независимо от того, использовался ли "/ p" или нет (модификатор
игнорируется), а "$` "," $ '"и $ & не вызывают разницы в скорости.
Без захвата группировки
Группа, которая требуется для объединения набора альтернатив, может быть полезной, а может и не быть полезной в качестве
группа захвата. Если это не так, он просто создает лишнее дополнение к набору
доступные значения группы захвата, как внутри, так и вне регулярного выражения. Без захвата
группировки, обозначенные "(?: regexp)", по-прежнему позволяют рассматривать регулярное выражение как единое целое,
но не создавайте одновременно группу захвата. И захват, и не захват
группировки могут сосуществовать в одном регулярном выражении. Потому что нет добычи,
группировки без захвата выполняются быстрее, чем группы с захватом. Не захватывающие группы
также удобен для выбора, какие именно части регулярного выражения должны быть извлечены для сопоставления
переменные:
# соответствует числу, установлено от 1 до 4 долларов, но нам нужен только 1 доллар
/ ([+ -]? \ * (\ d + (\. \ d *)? | \. \ d +) ([eE] [+ -]? \ d +)?) /;
# найти номер быстрее, устанавливается только $ 1
/ ([+ -]? \ * (?: \ d + (?: \. \ d *)? | \. \ d +) (?: [eE] [+ -]? \ d +)?) /;
# сопоставить число, получить $ 1 = целое число, $ 2 = показатель степени
/ ([+ -]? \ * (?: \ d + (?: \. \ d *)? | \. \ d +) (?: [eE] ([+ -]? \ d +))?) /;
Группы без захвата также полезны для удаления мешающих элементов, собранных из
операция разделения, где круглые скобки необходимы по какой-то причине:
$ x = '12aba34ba5';
@num = split / (a | b) + /, $ x; # @num = ('12', 'а', '34', 'а', '5')
@num = split / (?: a | b) + /, $ x; # @num = ('12', '34', '5')
В Perl 5.22 и более поздних версиях все группы в регулярном выражении могут быть отключены от захвата с помощью
новый флаг "/ n":
"привет" = ~ / (привет | привет) / н; # $ 1 не установлен!
См. "N" в perlre для получения дополнительной информации.
Согласование репетиции
Примеры в предыдущем разделе демонстрируют досадную слабость. Мы только соответствовали
Слова из 3 букв или отрывки слов из 4 букв или меньше. Мы хотели бы иметь возможность сопоставить
слова или, в более общем смысле, строки любой длины, без написания утомительных альтернатив
например "\ w \ w \ w \ w | \ w \ w \ w | \ w \ w | \ w".
В этом и заключается проблема количественного метасимволы "?", "*", "+" и "{}" были
создан для. Они позволяют нам ограничивать количество повторов для части регулярного выражения, которое мы
считать совпадением. Квантификаторы ставятся сразу после символа, символа
класс или группировка, которую мы хотим указать. Они имеют следующие значения:
· "А?" означает: сопоставить 'a' 1 или 0 раз
· «A *» означает: совпадение «a» 0 или более раз, т. Е. Любое количество раз
· "A +" означает: сопоставить "a" 1 или более раз, т.е. хотя бы один раз
· «A {n, m}» означает: совпадение не менее «n» раз, но не более «m» раз.
· "A {n,}" означает: совпадение не менее "n" или более раз
· "A {n}" означает: совпадение точно "n" раз
Вот несколько примеров:
/ [az] + \ s + \ d * /; # соответствует слову в нижнем регистре, по крайней мере, одному пробелу и
# любое количество цифр
/ (\ w +) \ s + \ g1 /; # сопоставить удвоенные слова произвольной длины
/да я; # соответствует 'y', 'Y' или 'да' без учета регистра
$ год = ~ / ^ \ d {2,4} $ /; # убедитесь, что год не меньше 2, но не больше
# более 4 цифр
$ год = ~ / ^ \ d {4} $ | ^ \ d {2} $ /; # лучшее совпадение; выбросить 3-значные даты
$ год = ~ / ^ \ d {2} (\ d {2})? $ /; # одно и то же написано по-разному.
# Однако это захватывает последние два
# цифр в $ 1, а остальные - нет.
% simple_grep '^ (\ w +) \ g1 $' / usr / dict / words # это не проще?
авитаминоз
гадостей
кокос
мама
Я бормочу
папа
Для всех этих квантификаторов Perl будет пытаться сопоставить как можно большую часть строки,
в то же время позволяя регулярному выражению успешно выполняться. Таким образом, с помощью "/a?.../" Perl сначала попытается
сопоставить регулярное выражение с присутствующим "а"; если это не удастся, Perl попытается сопоставить регулярное выражение
без подарка "а". Для квантификатора «*» мы получаем следующее:
$ x = "кот в шляпе";
$ x = ~ /^(.*)(cat)(.*)$/; # Матчи,
# $ 1 = 'the'
# $ 2 = 'кошка'
# $ 3 = 'в шапке'
Как и следовало ожидать, совпадение находит единственную «кошку» в строке и фиксируется на
Это. Однако рассмотрим это регулярное выражение:
$ x = ~ /^(.*)(at)(.*)$/; # Матчи,
# $ 1 = "кот в ч"
# $ 2 = 'в'
# $ 3 = '' (соответствует 0 символов)
Первоначально можно было предположить, что Perl найдет «at» в «cat» и остановится на этом, но это
не будет отдавать самую длинную строку первому квантификатору ". *". Вместо этого
первый квантификатор ". *" захватывает как можно большую часть строки, сохраняя при этом
регулярное выражение совпадение. В этом примере это означает наличие последовательности «at» с последним «at» в
Струна. Другой важный принцип, проиллюстрированный здесь, заключается в том, что когда есть два или
больше элементов в регулярном выражении, крайний слева квантификатор, если он есть, получает столько же
строки насколько это возможно, оставив остальную часть регулярного выражения бороться за записки. Таким образом, в
в нашем примере первый квантификатор ". *" захватывает большую часть строки, а второй
квантификатор ". *" получает пустую строку. Квантификаторы, которые захватывают столько же строки, сколько
возможные называются максимальный совпадение or жадный кванторы.
Когда регулярное выражение может соответствовать строке несколькими разными способами, мы можем использовать принципы
выше, чтобы предсказать, каким образом будет соответствовать регулярное выражение:
· Принцип 0: в целом любое регулярное выражение будет сопоставлено как можно раньше.
позиция в строке.
· Принцип 1. При чередовании «a | b | c ...» крайняя левая альтернатива, которая позволяет
совпадение для всего регулярного выражения будет использоваться.
· Принцип 2: Максимальные кванторы соответствия «?», «*», «+» И «{n, m}» будут в
общее соответствие как можно большей части строки, при этом разрешая все регулярное выражение
чтобы соответствовать.
· Принцип 3. Если в регулярном выражении два или более элементов, крайний левый жадный
квантификатор, если он есть, будет соответствовать как можно большей части строки, при этом разрешая
все регулярное выражение для соответствия. Следующий крайний левый жадный квантификатор, если он есть, попытается
соответствовать как можно большей части оставшейся строки, оставаясь при этом
позволяя всему регулярному выражению соответствовать. И так далее, пока все элементы регулярного выражения не будут
довольный.
Как мы видели выше, Принцип 0 имеет приоритет над остальными. Регулярное выражение будет соответствовать как
как можно раньше, с другими принципами, определяющими, как регулярное выражение совпадает с этим
самая ранняя позиция символа.
Вот пример этих принципов в действии:
$ x = "Республика программирования Perl";
$ x = ~ /^(.+)(e|r)(.*)$/; # Матчи,
# $ 1 = 'Программирующая республика Пе'
# $ 2 = 'г'
# $ 3 = 'l'
Это регулярное выражение соответствует самой ранней позиции строки, "T". Можно подумать, что "е", будучи
крайний левый в чередовании, будет сопоставлен, но "r" дает самую длинную строку в
первый квантор.
$ x = ~ /(m{1,2})(.*)$/; # Матчи,
# $ 1 = 'мм'
# $ 2 = "республика Perl"
Здесь самое раннее возможное совпадение - это первая буква «m» в слове «программирование». "m {1,2}" - это
первый квантор, поэтому он должен соответствовать максимальному «мм».
$ x = ~ /.* (m {1,2}) (. *) $ /; # Матчи,
# $ 1 = 'м'
# $ 2 = "республика Perl"
Здесь регулярное выражение соответствует началу строки. Первый квантификатор ". *" Записывается как
как можно больше, оставив только один "m" для второго квантификатора "m {1,2}".
$ x = ~ /(.?)(m{1,2})(.*)$/; # Матчи,
# $ 1 = 'а'
# $ 2 = 'мм'
# $ 3 = "республика Perl"
Здесь, ".?" съедает максимум один символ в самой ранней возможной позиции в строке,
"a" в "программировании", оставляя "m {1,2}" возможность совпадать с обоими "m". Наконец-то,
«aXXXb» = ~ / (X *) /; # совпадает с $ 1 = ''
потому что он может соответствовать нулевым копиям 'X' в начале строки. Если ты определенно
хотите сопоставить хотя бы один "X", используйте "X +", а не "X *".
Иногда жадность - это плохо. Иногда мы хотим, чтобы квантификаторы соответствовали минимальный кусок
струны, а не максимального отрезка. Для этого Ларри Уолл создал минимальный
совпадение or не жадный кванторы «??», «*?», «+?» и «{}?». Это обычные
кванторы с "?" прилагается к ним. Они имеют следующие значения:
· "А ??" означает: сопоставить 'a' 0 или 1 раз. Сначала попробуйте 0, затем 1.
· "А *?" означает: сопоставить 'a' 0 или более раз, т. е. любое количество раз, но столько раз, сколько
возможное
· "А +?" означает: сопоставить 'a' 1 или более раз, т. е. хотя бы один раз, но столько раз, сколько
возможное
· "А {п, м}?" означает: сопоставить не менее "n" раз, не более "m" раз, столько раз, сколько
возможное
· "А {п,}?" означает: найти как минимум n раз, но как можно меньше раз
· "А {п}?" означает: совпадение ровно "n" раз. Поскольку мы совпадаем ровно "n" раз, "a {n}?"
эквивалентно "a {n}" и служит только для согласованности обозначений.
Давайте посмотрим на приведенный выше пример, но с минимальными квантификаторами:
$ x = "Республика программирования Perl";
$ x = ~ /^(.+?)(e|r)(.*)$/; # Матчи,
# $ 1 = 'Th'
# $ 2 = 'е'
# $ 3 = 'республика программирования Perl'
Минимальная строка, которая разрешает как начало строки «^», так и чередование на
совпадение - «Th», с чередованием «e | r», совпадающим с «e». Второй квантификатор ". *" Равен
бесплатно, чтобы сожрать остаток струны.
$ x = ~ /(m{1,2}?)(.*?)$/; # Матчи,
# $ 1 = 'м'
# $ 2 = 'минская республика Perl'
Первая строковая позиция, которой может соответствовать это регулярное выражение, - это первая буква «m» в слове «программирование».
В этой позиции минимальный "m {1,2}?" соответствует только одному "м". Хотя второй
квантификатор ". *?" предпочел бы не соответствовать никаким символам, это ограничено концом-
привязка строки «$» для соответствия остальной части строки.
$ x = ~ /(.*?)(m{1,2}?)(.*)$/; # Матчи,
# $ 1 = "Программа"
# $ 2 = 'м'
# $ 3 = 'минская республика Perl'
В этом регулярном выражении вы можете ожидать первый минимальный квантификатор ". *?" чтобы соответствовать пустому
строка, потому что она не ограничена привязкой "^", чтобы соответствовать началу слова.
Однако здесь применяется принцип 0. Потому что все регулярное выражение может соответствовать
в начале строки предусматривает совпадение в начале строки. Таким образом, первая
квантификатор должен соответствовать всему до первого «m». Второй минимальный квантор
соответствует только одному "m", а третий квантификатор соответствует остальной части строки.
$ x = ~ /(.??)(m{1,2})(.*)$/; # Матчи,
# $ 1 = 'а'
# $ 2 = 'мм'
# $ 3 = "республика Perl"
Как и в предыдущем регулярном выражении, первый квантификатор ". ??" может соответствовать самому раннему в позиции
'а', так и есть. Второй квантификатор является жадным, поэтому соответствует "мм", а третий
соответствует остальной части строки.
Мы можем изменить принцип 3 выше, чтобы учесть не жадные кванторы:
· Принцип 3. Если в регулярном выражении два или более элементов, крайний левый жадный (не-
жадный) квантификатор, если таковой имеется, будет соответствовать как можно большему (меньшему) количеству строки
в то же время позволяя совпадать всему регулярному выражению. Следующий крайний левый жадный (нежадный)
квантификатор, если он есть, будет пытаться сопоставить столько (мало) оставшейся строки
доступный ему по мере возможности, при этом позволяя согласовывать все регулярное выражение. Так что
на, пока не будут удовлетворены все элементы регулярного выражения.
Как и чередование, кванторы также подвержены обратному отслеживанию. Вот шаг-
пошаговый разбор примера
$ x = "кот в шляпе";
$ x = ~ /^(.*)(at)(.*)$/; # Матчи,
# $ 1 = "кот в ч"
# $ 2 = 'в'
# $ 3 = '' (совпадений: 0)
0 Начните с первой буквы в строке «t».
1 Первый квантификатор '. *' Начинается с сопоставления всей строки 'кот в
шапка'.
2 'a' в элементе регулярного выражения 'at' не соответствует концу строки. Вернуться назад
характер.
3 'a' в элементе регулярного выражения 'at' по-прежнему не соответствует последней букве строки 't',
так что вернитесь еще на один символ.
4 Теперь мы можем сопоставить буквы «а» и «т».
5 Перейдите к третьему элементу '. *'. Поскольку мы находимся в конце строки и '. *' Можем
сопоставить 0 раз, присвоить ему пустую строку.
6 Готово!
В большинстве случаев все это движение вперед и возврат происходит быстро и поиск
быстро. Однако есть некоторые патологические регулярные выражения, время выполнения которых экспоненциально
растет с размером строки. Типичная структура, которая взрывается у вас на лице, - это
форма
/ (a | b +) * /;
Проблема заключается во вложенных неопределенных квантификаторах. Есть много разных способов
разделение строки длины n между «+» и «*»: одно повторение с «b +»
длина n, два повторения с первой длиной "b +" k и второй длиной nk, м
повторения, биты которых составляют в сумме длину n и т. д. На самом деле существует экспоненциальное число
способов разбиения строки в зависимости от ее длины. Регулярное выражение может оказаться удачным и
совпадают на ранней стадии процесса, но если совпадений нет, Perl попытается каждую возможность
прежде чем сдаться. Так что будьте осторожны с вложенными "*", "{n, m}" и "+". Книга
Освоение Стандарт Expressions Джеффри Фридл дает прекрасное обсуждение этого и
другие вопросы эффективности.
собственнический кванторы
Откатывание во время неустанного поиска совпадения может быть пустой тратой времени, особенно
когда матч обречен на провал. Рассмотрим простой шаблон
/ ^ \ w + \ s + \ w + $ /; # слово, пробелы, слово
Всякий раз, когда это применяется к строке, которая не совсем соответствует ожиданиям шаблона
например, "abc" или "abc def", механизм регулярных выражений выполнит возврат примерно один раз за
каждый символ в строке. Но мы знаем, что никуда не денешься ВСЕ
начальные символы слова, чтобы соответствовать первому повторению, что ВСЕ пробелы должны быть съедены
средняя часть, то же самое и со вторым словом.
С введением властно кванторы в Perl 5.10 у нас есть способ
указание механизму регулярных выражений не возвращаться, с обычными квантификаторами со знаком "+"
прилагается к ним. Это делает их не только скупыми, но и жадными; как только они добьются успеха, они не будут
отдать что-нибудь, чтобы разрешить другое решение. Они имеют следующие значения:
· "A {n, m} +" означает: сопоставить не менее "n" раз, не более "m" раз, столько раз, сколько
возможно, и не сдавайся. «a? +» - это сокращение от «a {0,1} +»
· "A {n,} +" означает: совпадать как минимум "n" раз, но как можно больше раз, и не
отказаться от чего-либо. «a * +» - это сокращение от «a {0,} +», а «a ++» - сокращение от «a {1,} +».
· «A {n} +» означает: совпадение ровно «n» раз. Это просто для согласованности обозначений.
Эти притяжательные кванторы представляют собой частный случай более общей концепции
независимые подвыражение, см. ниже.
В качестве примера, где подходит притяжательный квантор, мы рассматриваем сопоставление цитируемого
строка, как она появляется в нескольких языках программирования. Обратная косая черта используется как
escape-символ, который указывает, что следующий символ следует воспринимать буквально, как
другой символ для строки. Поэтому после вступительной цитаты мы ожидаем
(возможно, пустая) последовательность альтернатив: любой символ, кроме неэкранированной кавычки
или обратная косая черта, или экранированный символ.
/"(?:[^"\\ ]++|\\.)*+"/;
Здание a RegExp
На данный момент у нас есть все основные концепции регулярных выражений, поэтому давайте дадим больше
задействован пример регулярного выражения. Мы построим регулярное выражение, которое соответствует числам.
Первая задача при создании регулярного выражения - решить, что мы хотим сопоставить и что хотим.
исключать. В нашем случае мы хотим сопоставить как целые числа, так и числа с плавающей запятой, и мы
хотите отклонить любую строку, не являющуюся числом.
Следующая задача - разбить проблему на более мелкие, которые легко преобразовать.
в регулярное выражение.
Самый простой случай - целые числа. Они состоят из последовательности цифр с необязательным
подпишите вперед. Цифры, которые мы можем представить с помощью "\ d +", а знак может быть сопоставлен с
«[+ -]». Таким образом, целочисленное регулярное выражение равно
/ [+ -]? \ d + /; # соответствует целым числам
Число с плавающей запятой потенциально может иметь знак, целую часть, десятичную точку,
дробная часть и показатель степени. Одна или несколько из этих частей являются необязательными, поэтому нам нужно
проверьте различные возможности. Числа с плавающей запятой в правильной форме
включают 123., 0.345, 34, -1e6 и 25.4E-72. Как и в случае с целыми числами, спереди стоит знак
полностью необязательный и может быть заменен знаком «[+ -]?». Мы видим, что если нет
экспонента, числа с плавающей запятой должны иметь десятичную точку, в противном случае они являются целыми числами.
У нас может возникнуть соблазн смоделировать их с помощью "\ d * \. \ D *", но это также будет соответствовать просто
одна десятичная точка, которая не является числом. Итак, три случая чисел с плавающей запятой
без экспоненты
/ [+- ]?\d+\./; №1., 321. и т. Д.
/ [+- ]?\.\d+/; # .1, .234 и т. Д.
/ [+- ]?\d+\.\d+/; # 1.0, 30.56 и т. Д.
Их можно объединить в одно регулярное выражение с трехсторонним чередованием:
/ [+- ]?(\d+\.\d+|\d+\.|\.\d+)/; # с плавающей точкой, без экспоненты
В этом чередовании важно поставить '\ d + \. \ D +' перед '\ d + \.'. Если '\ d + \.' мы
Во-первых, регулярное выражение с радостью совпадет с этим и проигнорирует дробную часть числа.
Теперь рассмотрим числа с плавающей запятой с показателями степени. Ключевое наблюдение здесь заключается в том, что и
целые числа и числа с десятичной точкой разрешены перед экспонентой. потом
экспоненты, как и общий знак, не зависят от того, сопоставляем ли мы числа с
или без десятичных знаков, и может быть «отделен» от мантиссы. Общая форма
теперь регулярное выражение становится ясным:
/ ^ (необязательный знак) (целое число | мантисса fp) (необязательный показатель степени) $ /;
Показатель степени - это буква «е» или «E», за которой следует целое число. Таким образом, регулярное выражение экспоненты равно
/ [eE] [+ -]? \ d + /; # показатель
Собрав все части вместе, мы получим регулярное выражение, которое соответствует числам:
/^[+- provided?(\d+\.\d+|\d+\.|\.\d+|\d+)((eEpting[+-pting?\d+)?$/; # Да да!
Подобные длинные регулярные выражения могут произвести впечатление на ваших друзей, но их трудно расшифровать. В комплексе
В подобных ситуациях модификатор «// x» для совпадения неоценим. Это позволяет поставить
почти произвольные пробелы и комментарии в регулярном выражении, не влияя на их смысл.
Используя его, мы можем переписать наше «расширенное» регулярное выражение в более приятной форме.
/^
[+ -]? # сначала сопоставьте необязательный знак
(# затем сопоставьте целые числа или мантиссы fp:
\ d + \. \ d + # мантисса вида ab
| \ d + \. # мантисса формы a.
| \. \ d + # мантисса вида .b
| \ d + # целое число в форме a
)
([eE] [+ -]? \ d +)? # наконец, необязательно сопоставить экспоненту
$ / x;
Если пробелы в основном неактуальны, как включить пробелы в расширенный
регулярное выражение? Ответ - использовать обратную косую черту '\' или поместить в класс символов "[]". Одинаковый
это относится к знакам фунта: используйте «\ #» или «[#]». Например, Perl допускает пробел между
знак и мантисса или целое число, и мы могли бы добавить это к нашему регулярному выражению следующим образом:
/^
[+ -]? \ * # сначала укажите необязательный знак * и пробел *
(# затем сопоставьте целые числа или мантиссы fp:
\ d + \. \ d + # мантисса вида ab
| \ d + \. # мантисса формы a.
| \. \ d + # мантисса вида .b
| \ d + # целое число в форме a
)
([eE] [+ -]? \ d +)? # наконец, необязательно сопоставить экспоненту
$ / x;
В этой форме легче увидеть способ упростить чередование. Альтернативы 1, 2,
и 4 все начинаются с "\ d +", поэтому его можно вынести за скобки:
/^
[+ -]? \ * # сначала укажите необязательный знак
(# затем сопоставьте целые числа или мантиссы fp:
\ d + # начинаем с ...
(
\. \ d * # мантисса формы ab или a.
)? #? заботится о целых числах вида a
| \. \ d + # мантисса вида .b
)
([eE] [+ -]? \ d +)? # наконец, необязательно сопоставить экспоненту
$ / x;
или записано в компактной форме,
/ ^ [+ -]? \ * (\ d + (\. \ d *)? | \. \ d +) ([eE] [+ -]? \ d +)? $ /;
Это наше последнее регулярное выражение. Напомним, что мы построили регулярное выражение с помощью
· Детальное уточнение задачи,
· Разбиение проблемы на более мелкие части,
· Перевод мелких частей в регулярные выражения,
· Объединение регулярных выражений,
· И оптимизация итогового комбинированного регулярного выражения.
Это также типичные этапы написания компьютерной программы. Это делает
в идеальном смысле, потому что регулярные выражения - это, по сути, программы, написанные на небольшом
компьютерный язык, определяющий шаблоны.
. регулярный выражения in Perl
Последняя тема части 1 кратко описывает использование регулярных выражений в программах на Perl. Где делать
они вписываются в синтаксис Perl?
Мы уже ввели оператор сопоставления в его значение по умолчанию "/ regexp /" и произвольное
разделитель "m! regexp!" формы. Мы использовали оператор привязки «= ~» и его отрицание «! ~»
для проверки совпадений строк. Связанный с оператором сопоставления, мы обсудили
однострочный "// s", многострочный "// m", без учета регистра "// i" и расширенные модификаторы "// x".
Есть еще несколько вещей, которые вы, возможно, захотите узнать об операторах сопоставления.
Запрещающий замена
Если вы измените $ pattern после первой замены, Perl проигнорирует это. если ты
не хотите никаких замен, используйте специальный разделитель "m ''":
@pattern = ('Сьюз');
в то время как (<>) {
напечатать if m '@ pattern'; # соответствует буквальному "@pattern", а не "Seuss"
}
Подобно строкам, «m ''» действует как апостроф в регулярном выражении; все остальные разделители "m" действуют
как цитаты. Если регулярное выражение оценивается как пустая строка, регулярное выражение в последний
успешный совпадение вместо этого используется. Итак, у нас есть
«собака» = ~ / d /; # d совпадений
"dogbert = ~ //; # это соответствует регулярному выражению 'd', которое использовалось ранее
Глобальный согласование
Последние два модификатора, которые мы здесь обсудим, «// g» и «// c», относятся к нескольким совпадениям.
Модификатор «// g» обозначает глобальное сопоставление и позволяет оператору сопоставления сопоставлять
внутри строки столько раз, сколько возможно. В скалярном контексте последовательные вызовы
напротив строки будет иметь "// g" переход от совпадения к совпадению, отслеживая позицию в
струна по мере ее продвижения. Вы можете получить или установить позицию с помощью функции «pos ()».
Использование «// g» показано в следующем примере. Предположим, у нас есть строка,
состоит из слов, разделенных пробелами. Если мы заранее знаем, сколько слов есть, мы
мог извлекать слова, используя группировки:
$ x = "домик для кошек и собак"; # 3 слова
$ х = ~ / ^ \ s * (\ w +) \ s + (\ w +) \ s + (\ w +) \ s * $ /; # Матчи,
# $ 1 = 'кошка'
# $ 2 = 'собака'
# $ 3 = 'дом'
Но что, если бы у нас было неопределенное количество слов? Это своего рода задача "// g".
сделано для. Чтобы извлечь все слова, сформируйте простое регулярное выражение "(\ w +)" и переберите все совпадения.
с "/ (\ w +) / g":
в то время как ($ x = ~ / (\ w +) / g) {
print "Слово равно $ 1, заканчивается позицией", pos $ x, "\ n";
}
печать
Слово кошка, заканчивается на позиции 3
Слово собака, заканчивается на позиции 7
Слово дом, заканчивается на позиции 13
Неудачное совпадение или изменение целевой строки сбрасывают позицию. Если ты не хочешь
для сброса позиции после несоответствия добавьте «// c», как в «/ regexp / gc». Электрический ток
позиция в строке связана со строкой, а не с регулярным выражением. Это означает, что
разные струны имеют разные позиции, и их соответствующие позиции могут быть установлены или
читал самостоятельно.
В контексте списка "// g" возвращает список совпадающих группировок, или, если группировок нет,
список совпадений со всем регулярным выражением. Итак, если бы нам нужны были только слова, мы могли бы использовать
@words = ($ x = ~ / (\ w +) / g); # Матчи,
# $ words [0] = 'кошка'
# $ words [1] = 'собака'
# $ words [2] = 'дом'
С модификатором «// g» тесно связан якорь «\ G». Якорь "\ G" совпадает с
точка, в которой закончилось предыдущее совпадение "// g". "\ G" позволяет нам легко выполнять контекстные
чувствительное соответствие:
$ метрика = 1; # использовать метрические единицы
...
$ x = ; # читать в измерении
$ х = ~ / ^ ([+ -]? \ d +) \ s * / g; # получить величину
вес = 1 доллар;
if ($ metric) {# проверка ошибок
print "Ошибка единиц измерения!" если только $ x = ~ /\Gkg\./g;
}
еще {
print "Ошибка единиц измерения!" если только $ x = ~ /\Glbs\./g;
}
$ x = ~ / \ G \ s + (виджет | звездочка) / g; # продолжить обработку
Комбинация «// g» и «\ G» позволяет нам обрабатывать строку понемногу и использовать
произвольная логика Perl, чтобы решить, что делать дальше. В настоящее время привязка "\ G" только полностью
поддерживается, когда используется для привязки к началу рисунка.
"\ G" также бесценен при обработке записей фиксированной длины с помощью регулярных выражений. Предположим, у нас есть
фрагмент ДНК кодирующей области, закодированный буквами пары оснований "ATCGTTGAAT ...", и мы хотим
найти все стоп-кодоны «TGA». В кодирующей области кодоны представляют собой трехбуквенные последовательности, поэтому
мы можем думать о фрагменте ДНК как о последовательности трехбуквенных записей. Наивное регулярное выражение
# расширенный, это "ATC GTT GAA TGC AAA TGA CAT GAC"
$ dna = "ATCGTTGAATGCAAATGACATGAC";
$ dna = ~ / TGA /;
не работает; он может соответствовать "TGA", но нет гарантии, что совпадение совпадает
с границами кодонов, например, подстрока "GTT GAA" дает совпадение. Лучшее решение
while ($ dna = ~ / (\ w \ w \ w) *? TGA / g) {# обратите внимание на минимальное *?
print "Получил стоп-кодон TGA в позиции", pos $ dna, "\ n";
}
который печатает
Получил стоп-кодон TGA в позиции 18
Получил стоп-кодон TGA в позиции 23
Позиция 18 хороша, а позиция 23 - фальшивка. Что случилось?
Ответ заключается в том, что наше регулярное выражение работает хорошо, пока мы не пройдем последнее реальное совпадение. Тогда
regexp не сможет соответствовать синхронизированному "TGA" и начнет продвигаться вперед на один символ
позицию за раз, а не то, что мы хотим. Решение состоит в том, чтобы использовать "\ G", чтобы привязать совпадение к
выравнивание кодонов:
а ($ dna = ~ / \ G (\ w \ w \ w) *? TGA / g) {
print "Получил стоп-кодон TGA в позиции", pos $ dna, "\ n";
}
Это печатает
Получил стоп-кодон TGA в позиции 18
что и есть правильный ответ. Этот пример показывает, что важно не только
соответствовать желаемому, но отвергать нежелательное.
(Доступны и другие модификаторы регулярного выражения, такие как "// o", но их специализированные
использование выходит за рамки этого введения. )
Поиск и заменить
Регулярные выражения также играют большую роль в по области применения и заменить операции в Perl. Поиск
а замена выполняется с помощью оператора «s ///». Общая форма
"s / regexp / replacement / modifiers", со всем, что мы знаем о регулярных выражениях и модификаторах.
применяется и в этом случае. "Замена" - это строка Perl в двойных кавычках,
заменяет в строке все, что соответствует "регулярному выражению". Оператор "= ~" также
здесь используется для связывания строки с «s ///». Если совпадает с $ _, "$ _ = ~" может быть
упавший. Если есть совпадение, "s ///" возвращает количество сделанных замен; иначе
он возвращает false. Вот несколько примеров:
$ x = "Пора кормить кошку!";
$ x = ~ s / cat / hacker /; # $ x содержит "Пора кормить хакера!"
if ($ x = ~ s / ^ (Time. * hacker)! $ / $ 1 сейчас! /) {
$ more_insistent = 1;
}
$ y = "'цитируемые слова'";
$ y = ~ s /^'(.*)'$/$ 1 /; # удалить одинарные кавычки,
# $ y содержит "слова в кавычках"
В последнем примере была сопоставлена вся строка, но только часть внутри единственного
цитаты были сгруппированы. С оператором "s ///" совпадающие переменные $ 1, $ 2 и т. Д. Будут
немедленно доступны для использования в выражении замены, поэтому мы используем $ 1 для замены
строка в кавычках, содержащая только то, что было заключено в кавычки. С помощью глобального модификатора "s /// g" будет искать
и замените все вхождения регулярного выражения в строке:
$ x = "Я ответил 4 из 4";
$ x = ~ s / 4 / четыре /; # не все:
# $ x содержит "Я отбил четыре из четырех"
$ x = "Я ответил 4 из 4";
$ x = ~ s / 4 / четыре / г; # все это делает:
# $ x содержит "Я отбил четыре из четырех"
Если в этом руководстве вы предпочитаете «регулярное выражение», а не «регулярное выражение», вы можете использовать следующую программу
заменить его:
% cat> simple_replace
#!/ usr / bin / perl
$ regexp = сдвиг;
$ замена = сдвиг;
в то время как (<>) {
s / $ regexp / $ replace / g;
Распечатать;
}
^D
% simple_replace регулярное выражение регулярное выражение perlretut.pod
В "simple_replace" мы использовали модификатор "s /// g" для замены всех вхождений регулярного выражения
на каждой строке. (Несмотря на то, что регулярное выражение появляется в цикле, Perl достаточно умен
чтобы скомпилировать его только один раз.) Как и в случае с simple_grep, и print, и
"s / $ regexp / $ replace / g" неявно использует $ _.
Если вы не хотите, чтобы "s ///" изменял исходную переменную, вы можете использовать неразрушающий
замените модификатор "s /// r". Это изменяет поведение так, что "s /// r" возвращает последний
подставляемая строка (вместо количества замен):
$ x = "Я люблю собак.";
$ y = $ x = ~ s / собаки / кошки / r;
напечатать "$ x $ y \ n";
В этом примере будет напечатано «Я люблю собак. Я люблю кошек». Обратите внимание, что исходная переменная $ x имеет
не пострадали. Общий результат замены вместо этого сохраняется в $ y. Если
подстановка ни на что не влияет, тогда возвращается исходная строка:
$ x = "Я люблю собак.";
$ y = $ x = ~ s / слоны / пумы / r;
напечатать "$ x $ y \ n"; # отпечатки «Я люблю собак. Я люблю собак».
Еще одна интересная вещь, которую допускает флаг "s /// r", - это цепочка замен:
$ x = "Кошки прекрасны.";
напечатать $ x = ~ s / Cats / Dogs / r = ~ s / Dogs / Frogs / r = ~
s / Frogs / Hedgehogs / r, "\ n";
# отпечаток «Ежики молодцы».
Модификатор, доступный специально для поиска и замены, - это оценка "s /// e".
модификатор. "s /// e" обрабатывает заменяющий текст как код Perl, а не как двойные кавычки.
нить. Значение, возвращаемое кодом, заменяется совпадающей подстрокой.
"s /// e" полезно, если вам нужно произвести небольшие вычисления в процессе замены текста.
В этом примере подсчитывается частота символов в строке:
$ x = "Билет коту";
$ x = ~ s /(.)/$ chars {$ 1} ++; $ 1 / eg; # final $ 1 заменяет char на себя
print "частота '$ _' $ chars {$ _} \ n"
foreach (отсортировать {$ chars {$ b} <=> $ chars {$ a}} ключи% chars);
Это печатает
частота '' равна 2
частота 't' равна 2
частота l - 2
частота 'B' равна 1
частота 'c' равна 1
частота 'e' равна 1
частота 'h' равна 1
частота 'i' равна 1
частота 'а' равна 1
Как и в случае с оператором сопоставления «m //», «s ///» может использовать другие разделители, такие как «s !!!» а также
"s {} {}" и даже "s {} //". Если используются одинарные кавычки "s '' '", то регулярное выражение и
замены обрабатываются как строки в одинарных кавычках, и подстановки переменных отсутствуют.
"s ///" в контексте списка возвращает то же самое, что и в скалярном контексте, то есть количество
Матчи.
The раскол функция
Функция split () - еще одно место, где используется регулярное выражение. "разделить / регулярное выражение /, строка,
limit "разделяет" строковый "операнд на список подстрок и возвращает этот список.
Регулярное выражение должно быть спроектировано так, чтобы соответствовать тому, что составляет разделители для желаемого
подстроки. «Предел», если он присутствует, ограничивает разбиение на не более чем «предел»
количество струн. Например, чтобы разбить строку на слова, используйте
$ x = «Кальвин и Гоббс»;
@words = разделить / \ s + /, $ x; # $ word [0] = "Кальвин"
# $ word [1] = "и"
# $ word [2] = 'Гоббс'
Если используется пустое регулярное выражение "//", регулярное выражение всегда совпадает, и строка разбивается на
отдельные персонажи. Если в регулярном выражении есть группировки, то результирующий список содержит
также совпали подстроки из группировок. Например,
$ x = "/ usr / bin / perl";
@dirs = разделить m! / !, $ x; # $ dirs [0] = ''
# $ dirs [1] = 'usr'
# $ dirs [2] = 'корзина'
# $ dirs [3] = 'perl'
@parts = разделить m! (/) !, $ x; # $ parts [0] = ''
# $ parts [1] = '/'
# $ parts [2] = 'usr'
# $ parts [3] = '/'
# $ parts [4] = 'корзина'
# $ parts [5] = '/'
# $ parts [6] = 'perl'
Поскольку первый символ $ x соответствует регулярному выражению, "split" добавляется пустое начальное значение.
элемент в список.
Если вы дочитали до этого места, поздравляем! Теперь у вас есть все основные инструменты, необходимые для использования
регулярные выражения для решения широкого круга задач обработки текста. Если это твой
первый раз проработав руководство, почему бы не остановиться на этом и поиграть с регулярными выражениями a
while .... Часть 2 касается более эзотерических аспектов регулярных выражений и тех
концепции определенно не нужны с самого начала.
часть 2: Power инструменты
Хорошо, вы знаете основы регулярных выражений и хотите узнать больше. Если соответствует обычному
выражения аналогичны прогулке по лесу, тогда инструменты, обсуждаемые в Части 1, являются
аналогично топографическим картам и компасу, основным инструментам, которые мы используем постоянно. Большинство инструментов
в части 2 аналогичны сигнальным ракетам и спутниковым телефонам. Они не используются слишком часто на
поход, но когда мы застреваем, они могут оказаться бесценными.
Ниже приведены более продвинутые, менее используемые или иногда эзотерические возможности Perl.
регулярные выражения. В части 2 мы предполагаем, что вы знакомы с основами, и сконцентрируемся на
расширенные функции.
Ещё on персонажи, строки, и персонаж классов
Есть ряд escape-последовательностей и классов символов, которые мы еще не рассмотрели.
Есть несколько escape-последовательностей, которые преобразуют символы или строки между верхним и нижним
нижний регистр, и они также доступны в шаблонах. "\ l" и "\ u" преобразуют следующий
в нижний или верхний регистр соответственно:
$ x = "perl";
$ строка = ~ / \ u $ x /; # соответствует 'Perl' в строке $
$ x = "M (rs? | s) \\."; # обратите внимание на двойную обратную косую черту
$ строка = ~ / \ l $ x /; # соответствует 'mr.', 'mrs.' и 'ms.',
«\ L» или «\ U» указывают на продолжительное преобразование регистра, пока оно не будет прервано «\ E» или не будет сброшено.
на другой "\ U" или "\ L":
$ x = "Это слово в нижнем регистре: \ L SHOUT \ E";
$ x = ~ / крик /; # Матчи
$ x = "Я ЕЩЕ ОСТАЮСЬ КАРТОЧКИ ПЕРФОРАТОР ДЛЯ МОЕЙ 360"
$ x = ~ / \ Ukeypunch /; # соответствует строке перфокарты
Если нет "\ E", регистр преобразуется до конца строки. Регулярные выражения
"\ L \ u $ word" или "\ u \ L $ word" преобразуют первый символ $ word в верхний регистр, а остальные
символов в нижний регистр.
Управляющие символы могут быть экранированы с помощью "\ c", так что контрольный символ-Z будет
совпадает с "\ cZ". Управляющая последовательность "\ Q" ... "\ E" цитирует или защищает большинство не-
буквенные символы. Например,
$ x = "\ QThat! ^ * &% ~ & cat!";
$ x = ~ / \ Q! ^ * &% ~ & \ E /; # проверить грубую лексику
Он не защищает «$» или «@», так что переменные все же могут быть заменены.
«\ Q», «\ L», «\ l», «\ U», «\ u» и «\ E» на самом деле являются частью синтаксиса двойных кавычек, а не
часть собственно синтаксиса регулярного выражения. Они будут работать, если появятся в регулярном выражении.
встроен непосредственно в программу, но не когда содержится в строке, которая интерполируется в
шаблон.
Регулярные выражения Perl могут обрабатывать не только стандартный набор символов ASCII. Perl поддерживает
Unicode, стандарт для представления алфавитов практически всех стран мира
письменные языки и множество символов. Текстовые строки Perl - это строки Unicode, поэтому
они могут содержать символы со значением (кодовая точка или номер символа) выше 255.
Что это значит для регулярных выражений? Ну, пользователям регулярных выражений не нужно много знать о Perl
внутреннее представление строк. Но им нужно знать 1) как представлять Unicode.
символов в регулярном выражении и 2) что операция сопоставления будет рассматривать строку как
ищется как последовательность символов, а не байтов. Ответ на 1) заключается в том, что Unicode
символы больше чем "CHR(255) "представлены с использованием обозначения" \ x {шестнадцатеричный} ", потому что
\ x hex (без фигурных скобок) не превышает 255. (Начиная с Perl 5.14, если
вы поклонник восьмеричного числа, вы также можете использовать "\ o {oct}".)
/ \ x {263a} /; # сопоставить смайлик Unicode :)
ЗАМЕТКА: В Perl 5.6.0 раньше требовалось сказать «используйте utf8» для использования любого Unicode
Особенности. Это уже не так: почти для всей обработки Unicode явное
Прагма "utf8" не нужна. (Единственный случай, когда это имеет значение, если ваш Perl-скрипт находится в
Unicode и кодируется в UTF-8, тогда требуется явное использование utf8.)
Выяснение шестнадцатеричной последовательности нужного символа Юникода или расшифровка
чужое шестнадцатеричное регулярное выражение Unicode примерно так же весело, как программирование на машине
код. Таким образом, еще один способ указать символы Unicode - использовать названный персонаж бежать
последовательность "\ N {имя}". имя это имя для символа Юникода, как указано в
Стандарт Юникода. Например, если мы хотим представить или сопоставить астрологический знак
для планеты Меркурий мы могли бы использовать
$ x = "abc \ N {MERCURY} def";
$ x = ~ / \ N {МЕРКУРИЙ} /; # Матчи
Также можно использовать «короткие» имена:
print "\ N {ГРЕЧЕСКАЯ СТРОЧНАЯ БУКВА СИГМА} называется сигмой. \ n";
print "\ N {greek: Sigma} - это сигма в верхнем регистре. \ n";
Вы также можете ограничить имена определенным алфавитом, указав прагму charnames:
используйте charnames qw (греческий);
print "\ N {sigma} - греческая сигма \ n";
Указатель имен символов доступен в режиме онлайн в Консорциуме Unicode,
<http://www.unicode.org/charts/charindex.html>; пояснительный материал со ссылками на другие
ресурсы наhttp://www.unicode.org/standard/where>.
Ответ на требование 2) заключается в том, что регулярное выражение (в основном) использует символы Юникода. В
"в основном" используется из соображений обратной совместимости, но начиная с Perl 5.14 любое регулярное выражение
скомпилирован в рамках «функции использования unicode_strings» (которая автоматически включается
on в рамках «использовать 5.012» или выше) превратит это «в основном» в «всегда». Если
вы хотите правильно обрабатывать Unicode, вы должны убедиться, что unicode_strings включен
на. Внутренне это кодируется в байты с использованием либо UTF-8, либо собственной 8-битной кодировки,
в зависимости от истории строки, но концептуально это последовательность символов,
не байты. См. Руководство по этому поводу в perlunitut.
Давайте теперь обсудим классы символов Unicode, которые чаще всего называются «свойствами символов».
Они представлены управляющей последовательностью "\ p {name}". Тесно связан
Свойство "\ P {name}", которое является отрицанием свойства "\ p {name}". Например, чтобы соответствовать
строчные и прописные буквы,
$ x = "БОБ";
$ x = ~ / ^ \ p {IsUpper} /; # совпадений, класс символов в верхнем регистре
$ x = ~ / ^ \ P {IsUpper} /; # не совпадает, класс символов без верхнего регистра
$ x = ~ / ^ \ p {IsLower} /; # не соответствует классу символов нижнего регистра
$ x = ~ / ^ \ P {IsLower} /; # совпадений, класс символов без нижнего регистра
(«Is» не является обязательным.)
Есть много-много свойств символов Юникода. Полный список см. В perluniprops.
У большинства из них есть синонимы с более короткими названиями, также перечисленные там. Некоторые синонимы - это
одиночный персонаж. Для них вы можете отказаться от подтяжек. Например, "\ pM" то же самое
как "\ p {Mark}", что означает такие вещи, как знаки ударения.
Свойство Unicode "\ p {Script}" используется для классификации каждого символа Unicode в
языковой сценарий, на котором он написан. Например, английский, французский и многие другие
Европейские языки пишутся латиницей. Но есть еще греческий шрифт,
тайский сценарий, сценарий катакана и т. д. Вы можете проверить, находится ли персонаж в
конкретный сценарий с, например, "\ p {Latin}", "\ p {Greek}" или "\ p {Katakana}". Тестировать
если этого нет в балийском сценарии, вы должны использовать "\ P {Balinese}".
То, что мы описали до сих пор, является единственной формой классов символов "\ p {...}".
Есть также составная форма, с которой вы можете столкнуться. Они выглядят как "\ p {name = value}" или
"\ p {name: value}" (знак равенства и двоеточие могут использоваться как синонимы). Это больше
больше, чем отдельная форма, и на самом деле большинство отдельных форм просто определены Perl
ярлыки для распространенных составных форм. Например, примеры скриптов в предыдущем
абзац может быть записан эквивалентно как "\ p {Script = Latin}", "\ p {Script: Greek}",
"\ p {script = katakana}" и "\ P {script = balinese}" (регистр между "{}" не имеет значения
подтяжки). Возможно, вам никогда не придется использовать составные формы, но иногда это необходимо, и
их использование может облегчить понимание вашего кода.
"\ X" - это аббревиатура для класса символов, который включает Unicode. расширенная графема
кластер. Это представляет собой "логический символ": то, что кажется одним символом,
но может быть представлен внутри более чем одним. В качестве примера, используя полный Unicode
имена, например, «A + COMBINING RING» - это кластер графемы с базовым символом «A» и
объединяющий символ "КОМБИНИРУЮЩЕЕ КОЛЬЦО", что на датском переводится как А с кружком наверху
это, как в слове Aangstrom.
Для получения полной и последней информации о Unicode см. Последний стандарт Unicode или
Сайт Консорциума Unicodehttp://www.unicode.org>
Как будто всех этих классов было недостаточно, Perl также определяет классы символов в стиле POSIX.
Они имеют форму «[: name:]», где «name» - это имя класса POSIX. POSIX
классы: "alpha", "alnum", "ascii", "cntrl", "digit", "graph", "lower", "print",
«punct», «space», «upper» и «xdigit», а также два расширения, «word» (расширение Perl для
соответствует "\ w") и "blank" (расширение GNU). Модификатор "// a" ограничивает их
соответствие только в диапазоне ASCII; в противном случае они могут совпадать с соответствующими
Классы Unicode Perl: "[: upper:]" то же самое, что "\ p {IsUpper}" и т. Д. (Есть некоторые
исключения и подводные камни с этим; см. perlrecharclass для полного обсуждения.)
«[: digit:]», «[: word:]» и «[: space:]» соответствуют знакомым «\ d», «\ w» и «\ s»
классы персонажей. Чтобы исключить класс POSIX, поставьте перед именем "^", чтобы
например, «[: ^ digit:]» соответствует «\ D», а в Unicode - «\ P {IsDigit}». Юникод и
Классы символов POSIX могут использоваться так же, как "\ d", за исключением того, что POSIX
классы символов могут использоваться только внутри класса символов:
/ \ s + [abc [: digit:] xyz] \ s * /; # соответствует a, b, c, x, y, z или цифре
/ ^ = элемент \ s [[: цифра:]] /; # match '= item',
#, за которым следует пробел и цифра
/ \ s + [abc \ p {IsDigit} xyz] \ s + /; # соответствует a, b, c, x, y, z или цифре
/ ^ = элемент \ s \ p {IsDigit} /; # match '= item',
#, за которым следует пробел и цифра
Ух! Это все остальные персонажи и классы персонажей.
составление и экономия регулярный выражения
В Части 1 мы упоминали, что Perl компилирует регулярное выражение в компактную последовательность кодов операций.
Таким образом, скомпилированное регулярное выражение - это структура данных, которую можно сохранить один раз и использовать снова и
снова. Цитата регулярного выражения «qr //» делает именно это: «qr / string /» компилирует «строку» как
regexp и преобразует результат в форму, которую можно присвоить переменной:
$ reg = qr / foo + bar? /; # reg содержит скомпилированное регулярное выражение
Тогда $ reg можно использовать как регулярное выражение:
$ x = "fooooba";
$ x = ~ $ reg; # совпадений, как / foo + bar? /
$ x = ~ / $ reg /; # то же самое, альтернативная форма
$ reg также можно интерполировать в более крупное регулярное выражение:
$ x = ~ / (abc)? $ reg /; # еще совпадений
Как и в случае с оператором сопоставления, цитата регулярного выражения может использовать разные разделители, например,
«qr !!», «qr {}» или «qr ~~». Апострофы как разделители («qr ''») запрещают любую интерполяцию.
Предварительно скомпилированные регулярные выражения полезны для создания динамических совпадений, которые не нужно
перекомпилируется каждый раз, когда они встречаются. Используя предварительно скомпилированные регулярные выражения, мы пишем
Программа "grep_step", которая ищет последовательность шаблонов, переходя к следующему шаблону.
как только он будет удовлетворен.
% cat> grep_step
#!/ usr / bin / perl
# grep_step - совпадение регулярные выражения, одно за другим
# использование: multi_grep регулярное выражение1 регулярное выражение2 ... файл1 файл2 ...
$ число = сдвиг;
$ regexp [$ _] = сдвиг foreach (0 .. $ number-1);
@compiled = map qr / $ _ /, @regexp;
while ($ line = <>) {
if ($ line = ~ / $ compiled [0] /) {
print $ line;
сдвиг @скомпилированный;
последний, если не @compiled;
}
}
^D
% grep_step 3 shift печатать последний grep_step
$ число = сдвиг;
print $ line;
последний, если не @compiled;
Хранение предварительно скомпилированных регулярных выражений в массиве @compiled позволяет нам просто перебрать
regexps без перекомпиляции, что обеспечивает гибкость без ущерба для скорости.
составление регулярный выражения at время выполнения
Поиск с возвратом более эффективен, чем повторные попытки с разными регулярными выражениями. Если
есть несколько регулярных выражений и соответствие любому из них допустимо, тогда это
их можно объединить в набор альтернатив. Если отдельные выражения
входных данных, это можно сделать, запрограммировав операцию соединения. Мы будем использовать эту идею в
улучшенная версия программы "simple_grep": программа, которая соответствует нескольким
шаблоны:
% cat> multi_grep
#!/ usr / bin / perl
# multi_grep - соответствует любому из регулярные выражения
# использование: multi_grep регулярное выражение1 регулярное выражение2 ... файл1 файл2 ...
$ число = сдвиг;
$ regexp [$ _] = сдвиг foreach (0 .. $ number-1);
$ шаблон = соединение '|', @regexp;
while ($ line = <>) {
напечатать $ line, если $ line = ~ / $ pattern /;
}
^D
% multi_grep 2 сдвиг для multi_grep
$ число = сдвиг;
$ regexp [$ _] = сдвиг foreach (0 .. $ number-1);
Иногда бывает выгодно построить узор из вход что подлежит анализу
и используйте допустимые значения в левой части операций сопоставления. Как
пример для этой несколько парадоксальной ситуации, предположим, что наш ввод содержит
командный глагол, который должен соответствовать одному из набора доступных командных глаголов, с
дополнительный поворот в том, что команды могут быть сокращены до тех пор, пока данная строка уникальна.
Программа ниже демонстрирует основной алгоритм.
% cat> совпадение клавиш
#!/ usr / bin / perl
$ kwds = 'копировать список сравнения печать';
в то время как ($ cmd = <>) {
$ cmd = ~ s / ^ \ s + | \ s + $ // g; # обрезать начальные и конечные пробелы
if ((@matches = $ kwds = ~ / \ b $ cmd \ w * / g) == 1) {
print "команда: '@matches' \ n";
} elsif (@matches == 0) {
print "такой команды нет: '$ cmd' \ n";
} Еще {
print "не уникально: '$ cmd' (может быть одним из: @matches) \ n";
}
}
^D
% совпадение клавиш
li
команда: 'список'
co
не уникально: 'co' (может быть одним из: копировать, сравнить)
принтер
нет такой команды: 'принтер'
Вместо того, чтобы пытаться сопоставить ввод с ключевыми словами, мы сопоставляем объединенный набор
ключевые слова против ввода. Операция сопоставления с образцом "$ kwds = ~ / \ b ($ cmd \ w *) / g" выполняет
несколько вещей одновременно. Это гарантирует, что данная команда начинается там, где
ключевое слово начинается ("\ b"). Допускается использование сокращений из-за добавления «\ w *». Это говорит нам о
количество совпадений ("скалярные @ совпадения") и все фактически совпавшие ключевые слова.
Вы вряд ли могли бы желать большего.
Встраивание Комментарии и модификаторы in a регулярный выражение
Начиная с этого раздела, мы будем обсуждать набор Perl расширенная паттеранами, Эти
являются расширениями традиционного синтаксиса регулярных выражений, которые обеспечивают новые мощные
инструменты для сопоставления с образцом. Мы уже видели расширения в виде минимального
соответствующие конструкции «??», «*?», «+?», «{n, m}?» и «{n,}?». Большинство расширений ниже
имеют форму "(? char ...)", где "char" - это символ, определяющий тип
расширение.
Первое расширение - это встроенный комментарий «(? #Text)». Это вставляет комментарий в
регулярное выражение, не влияя на его смысл. Комментарий не должен закрываться
круглые скобки в тексте. Примером является
/ (? # Соответствует целому числу :) [+ -]? \ D + /;
Этот стиль комментирования был в значительной степени вытеснен необработанными комментариями в произвольной форме, что
допускается с модификатором «// x».
Большинство модификаторов, таких как «// i», «// m», «// s» и «// x» (или любая их комбинация) могут
также быть встроенным в регулярное выражение с использованием «(? i)», «(? m)», «(? s)» и «(? x)». Например,
/(?я да/; # соответствует 'да' без учета регистра
/да я; # то же самое
/ (? x) (# произвольная версия целочисленного регулярного выражения
[+ -]? # соответствует необязательному знаку
\ d + # соответствует последовательности цифр
)
/Икс;
Встроенные модификаторы могут иметь два важных преимущества перед обычными модификаторами. Встроенный
модификаторы позволяют настраивать набор модификаторов для каждый шаблон регулярного выражения. Это отлично подходит для
сопоставление массива регулярных выражений, у которых должны быть разные модификаторы:
$ pattern [0] = '(? i) доктор';
$ pattern [1] = 'Джонсон';
...
в то время как (<>) {
foreach $ patt (@pattern) {
напечатать if / $ patt /;
}
}
Второе преимущество заключается в том, что встроенные модификаторы (кроме "// p", изменяющей все
regexp) влияет только на регулярное выражение внутри группы, в которой содержится встроенный модификатор. Итак
группировка может использоваться для локализации эффектов модификатора:
/ Ответ: ((? I) да) /; # соответствует 'Ответ: да', 'Ответ: ДА' и т. д.
Встроенные модификаторы также могут отключить любые уже существующие модификаторы, используя, например,
"(?-я)". Модификаторы также можно объединить в одно выражение, например "(? Si)" включает
однострочный режим и отключает нечувствительность к регистру.
Встроенные модификаторы также могут быть добавлены в группу без захвата. "(? im: regexp)" - это
группировка без захвата, которая нечувствительна к регистру "regexp" и отключает многострочность
Режим.
Глядя впереди и искать за
Этот раздел касается утверждений просмотра вперед и назад. Во-первых, немного
фон.
В регулярных выражениях Perl большинство элементов регулярных выражений "съедают" определенное количество строк, когда
они совпадают. Например, элемент регулярного выражения "[abc}]" поглощает один символ строки.
когда он совпадает, в том смысле, что Perl переходит к позиции следующего символа в строке
после матча. Однако есть некоторые элементы, которые не съедают персонажей (заранее
позиция символа), если они совпадают. Примеры, которые мы видели до сих пор, - это якоря.
Якорь «^» соответствует началу строки, но не содержит никаких символов.
Точно так же привязка границы слова "\ b" совпадает с любым совпадающим символом "\ w"
рядом с персонажем, которого нет, но он сам не съедает никаких персонажей. Якоря
примеры нулевая ширина утверждения: нулевой ширины, потому что они не используют символы, и
утверждения, потому что они проверяют какое-то свойство строки. В контексте нашей прогулки в
аналогия леса с сопоставлением регулярных выражений, большинство элементов регулярных выражений перемещают нас по тропе, но
якоря заставляют нас остановиться на мгновение и осмотреть окрестности. Если локальная среда проверяет
, мы можем двигаться дальше. Но если местная среда нас не удовлетворяет, мы должны
отступить.
Чтобы проверить окружающую среду, нужно либо смотреть вперед по тропе, либо оглядываться назад, либо
оба. «^» оглядывается назад, чтобы убедиться, что перед ним нет символов. «$» смотрит вперед, чтобы
убедитесь, что после него нет символов. "\ b" смотрит вперед и назад, чтобы убедиться, что
символы с обеих сторон различаются своей «словесностью».
Утверждения просмотра вперед и назад являются обобщением концепции привязки.
Lookahead и lookbehind - утверждения нулевой ширины, которые позволяют нам указывать, какие символы мы
хочу проверить. Утверждение просмотра вперед обозначается "(? = Regexp)", а утверждение просмотра назад
утверждение обозначается как «(? <= fixed-regexp)». Некоторые примеры
$ x = "Я ловлю домашнюю кошку" Кот-кот "кошачьей мятой";
$ х = ~ / кошка (? = \ s) /; # соответствует 'cat' в 'housecat'.
@catwords = ($ x = ~ / (? <= \ s) кошка \ w + / g); # Спички,
# $ catwords [0] = 'улов'
# $ catwords [1] = 'кошачья мята'
$ х = ~ / \ bcat \ b /; # соответствует 'cat' в 'Tom-cat'
$ х = ~ / (? <= \ s) кошка (? = \ s) /; # не совпадает; нет изолированной «кошки» в
# середина $ x
Обратите внимание, что круглые скобки в "(? = Regexp)" и "(? <= Regexp)" не захватывают, поскольку эти
являются утверждениями нулевой ширины. Таким образом, во втором регулярном выражении захваченные подстроки - это те
всего регулярного выражения. Lookahead "(? = Regexp)" может соответствовать произвольным регулярным выражениям, но
lookbehind "(? <= fixed-regexp)" работает только для регулярных выражений фиксированной ширины, т. е. фиксированного числа
символов длинные. Таким образом, «(? <= (Ab | bc))» подходит, а «(? <= (Ab) *)» - нет. Отрицательный
версии утверждений просмотра вперед и назад обозначаются "(?! regexp)" и
"(? игра:
$ x = "foobar";
$ x = ~ / foo (?! бар) /; # не совпадает, 'bar' следует за 'foo'
$ x = ~ / foo (?! баз) /; # совпадений, 'baz' не следует за 'foo'
$ x = ~ / (?
"\ C" не поддерживается при просмотре назад, потому что и без того коварное определение "\ C"
станет еще больше при движении назад.
Вот пример, где строка, содержащая слова, разделенные пробелами, числа и одиночные
тире следует разбивать на его составляющие. Использование одного "/ \ s + /" не сработает, потому что пробелы
не требуются между тире, словом или тире. Дополнительные места для шпагата есть
установлено, глядя вперед и назад:
$ str = "один два - --6-8";
@toks = split / \ s + # пробелы
| (? <= \ S) (? = -) # любые непробелы, за которыми следует '-'
| (? <= -) (? = \ S) # '-', за которым следует любое непробельное
/ x, $ str; # @toks = qw (один два - - - 6-8)
. независимые подвыражения в предотвращать возвраты
Независмая платформа подвыражения являются регулярными выражениями в контексте более крупных регулярных
выражение, которое функционирует независимо от более крупного регулярного выражения. То есть они
потребляют столько или меньше струны, сколько хотят, без учета способности
большее регулярное выражение для соответствия. Независимые подвыражения представлены «(?> Regexp)».
Мы можем проиллюстрировать их поведение, сначала рассмотрев обычное регулярное выражение:
$ x = "ab";
$ x = ~ / a * ab /; # Спички
Это, очевидно, совпадает, но в процессе сопоставления сначала подвыражение "a *"
схватил "а". Однако это не приведет к совпадению всего регулярного выражения, поэтому после
при поиске с возвратом "a *" в конечном итоге вернул "a" и сопоставил пустую строку. Вот что
совпадение "a *" было зависимый на что совпало остальное регулярное выражение.
Сравните это с независимым подвыражением:
$ x = ~ / (?> a *) ab /; # не совпадает!
Независимое подвыражение "(?> A *)" не влияет на остальную часть регулярного выражения, поэтому оно
видит "а" и хватается за нее. Тогда остальная часть регулярного выражения «ab» не может совпадать. Так как
"(?> a *)" является независимым, нет возврата и независимое подвыражение выполняет
не отказываться от своего "а". Таким образом, совпадение регулярного выражения в целом не выполняется. Подобное поведение
происходит с полностью независимыми регулярными выражениями:
$ x = "ab";
$ х = ~ / а * / г; # совпадает, ест "а"
$ х = ~ / \ Габ / г; # не совпадает, нет доступных 'a'
Здесь «// g» и «\ G» создают «команду тегов», передающую строку из одного регулярного выражения в
разное. Регулярные выражения с независимым подвыражением очень похожи на это, с передачей
строка в независимое подвыражение и передача строки обратно в
включающее регулярное выражение.
Способность независимого подвыражения предотвращать возврат с возвратом может быть весьма полезной.
Предположим, мы хотим сопоставить непустую строку, заключенную в круглые скобки, глубиной до двух уровней.
Тогда соответствует следующее регулярное выражение:
$ x = "abc (de (fg) h"; # несбалансированные круглые скобки
$ х = ~ / \ (([^ ()] + | \ ([^ ()] * \)) + \) / х;
Регулярное выражение соответствует открытой круглой скобке, одной или нескольким копиям чередования и закрытию
скобка. Чередование двустороннее: первая альтернатива «[^ ()] +» соответствует
подстрока без скобок и вторая альтернатива «\ ([^ ()] * \)», соответствующая
подстрока, ограниченная круглыми скобками. Проблема с этим регулярным выражением в том, что оно
патологический: он имеет вложенные неопределенные кванторы формы «(a + | b) +». Мы обсудили
в Части 1 показано, как вложенным квантификаторам может потребоваться экспоненциально много времени, чтобы
выполнить, если совпадение невозможно. Чтобы предотвратить экспоненциальный взрыв, нам нужно
предотвратить бесполезный возврат в какой-то момент. Это можно сделать, заключив внутренний
квантификатор как независимое подвыражение:
$ х = ~ / \ (((?> [^ ()] +) | \ ([^ ()] * \)) + \) / х;
Здесь "(?> [^ ()] +)" Нарушает вырождение разделения строк, поглощая столько же
шнурок по возможности и удерживая его. Тогда неудачные совпадения терпят неудачу намного быстрее.
Условный выражения
A условный выражение это форма оператора if-then-else, позволяющая выбирать
какие шаблоны должны быть сопоставлены, в зависимости от некоторого условия. Есть два типа
условное выражение: "(? (условие) yes-regexp)" и
"(? (условие) yes-regexp | no-regexp)". "(? (условие) yes-regexp)" похоже на 'if () {}'
заявление на Perl. Если «условие» истинно, будет выполнено «да-регулярное выражение». Если
"condition" ложно, "yes-regexp" будет пропущено, и Perl перейдет к следующему
элемент регулярного выражения. Вторая форма похожа на оператор if () {} else {} в Perl. Если
"condition" истинно, "yes-regexp" будет совпадать, в противном случае "no-regexp" будет
соответствует.
«Условие» может иметь несколько форм. Первая форма - это просто целое число в
круглые скобки "(целое число)". Верно, если соответствующая обратная ссылка "\ integer" соответствует
ранее в регулярном выражении. То же самое можно сделать с именем, связанным с захватом.
группа, записанная как "( ) "или" ('name') ". Вторая форма - это пустой
утверждение "(? ...)", либо предварительный просмотр, либо утверждение кода (обсуждается в
следующий раздел). Третий набор форм предоставляет тесты, которые возвращают истину, если
выражение выполняется в рекурсии ("(R)") или вызывается из некоторого захвата
группа, на которую ссылаются либо по номеру («(R1)», «(R2)», ...), либо по имени («(R & name)»).
Целочисленная или именная форма "условия" позволяет нам выбирать с большей гибкостью,
что сопоставить на основе того, что сопоставлено ранее в регулярном выражении. Это ищет слова
форма "$ x $ x" или "$ x $ y $ y $ x":
% simple_grep '^ (\ w +) (\ w +)? (? (2) \ g2 \ g1 | \ g1) $' / usr / dict / слова
авитаминоз
кокос
кускус
дело
...
гудок
тото
пачка
«Условие» просмотра назад позволяет, наряду с обратными ссылками, более раннюю часть совпадения.
чтобы повлиять на более позднюю часть матча. Например,
/ [ATGC] + (? (? <= AA) G | C) $ /;
совпадает с последовательностью ДНК, так что она либо заканчивается на «AAG», либо на какую-либо другую пару оснований
сочетание и "С". Обратите внимание, что это форма «(? (? <= AA) G | C)», а не «(? ((? <= AA)) G | C)»; за
утверждения предварительного просмотра, просмотра назад или кода, круглые скобки вокруг условного выражения
не требуется.
Определяющий названный паттеранами
Некоторые регулярные выражения используют идентичные подшаблоны в нескольких местах. Начиная с Perl
5.10, можно определить именованные подшаблоны в части шаблона, чтобы они
может быть вызван по имени в любом месте шаблона. Этот синтаксический шаблон для этого
группа определения "(? (DEFINE) (? шаблон) ...) ". Вставка именованного шаблона
записывается как «(? & имя)».
Пример ниже иллюстрирует эту функцию с использованием шаблона для чисел с плавающей запятой.
который был представлен ранее. Три подшаблона, которые используются более одного раза, являются
необязательный знак, последовательность цифр для целого числа и десятичной дроби. ОПРЕДЕЛЕНИЕ
группа в конце паттерна содержит их определение. Обратите внимание, что десятичный
Шаблон дроби - это первое место, где мы можем повторно использовать целочисленный шаблон.
/ ^ (? & osg) \ * ((? & int) (? & dec)? | (? & dec))
(?: [eE] (? & osg) (? & int))?
$
(?(ОПРЕДЕЛЯТЬ)
(? [- +]?) # необязательный знак
(? \ d ++) # целое число
(? \. (? & int)) # десятичная дробь
)/Икс
рекурсивный паттеранами
Эта функция (представленная в Perl 5.10) значительно расширяет возможности шаблона Perl.
соответствие. Ссылаясь на какую-либо другую группу захвата в любом месте шаблона с
построить "(? group-ref)", описания в указанной группе используется как
независимый подшаблон вместо самой ссылки на группу. Потому что группа
ссылка может содержаться одной группа, к которой он относится, теперь можно применить
сопоставление шаблонов с задачами, которые до сих пор требовали рекурсивного синтаксического анализатора.
Чтобы проиллюстрировать эту функцию, мы разработаем шаблон, который соответствует, если строка содержит
палиндром. (Это слово или предложение, в котором без учета пробелов вставка
и case, то же самое, что и вперед, и назад. Начнем с того, что заметим, что пустой
строка или строка, содержащая только один символ слова, является палиндромом. В противном случае он должен
иметь символ слова впереди и то же самое в конце, с другим палиндромом в
между.
/ (?: (\ w) (? ... Вот палиндром ...) \ g {-1} | \ w?) / x
Добавив "\ W *" на обоих концах, чтобы исключить то, что следует игнорировать, у нас уже есть полный
шаблон:
мой $ pp = qr / ^ (\ W * (?: (\ w) (? 1) \ g {-1} | \ w?) \ W *) $ / ix;
for $ s ("saippuakauppias", "Человек, план, канал: Панама!") {
print "'$ s' - это палиндром \ n", если $ s = ~ / $ pp /;
}
В "(? ...)" могут использоваться как абсолютные, так и относительные обратные ссылки. Весь узор может
быть повторно вставленным с помощью "(? R)" или "(? 0)". Если вы предпочитаете называть свои группы, вы можете использовать
«(? & name)», чтобы вернуться в эту группу.
A бит of магия: проведение Perl код in a регулярный выражение
Обычно регулярные выражения являются частью выражений Perl. Code оценка выражения превращают это
вокруг, позволяя произвольному коду Perl быть частью регулярного выражения. Оценка кода
выражение обозначается "(? {code})", с код строка операторов Perl.
Имейте в виду, что эта функция считается экспериментальной и может быть изменена без предварительного уведомления.
Кодовые выражения представляют собой утверждения нулевой ширины, и возвращаемое ими значение зависит от их
окружающая обстановка. Есть две возможности: либо кодовое выражение используется как
условное выражение в условном выражении "(? (условие) ...)", или это не так. Если код
выражение является условным, код оценивается и результат (т. е. результат
последнее утверждение) используется для определения истины или лжи. Если кодовое выражение не
используется как условие, утверждение всегда оценивается как истина, а результат помещается в
специальная переменная $ ^ R. Затем переменную $ ^ R можно будет использовать в кодовых выражениях позже в
регулярное выражение. Вот несколько глупых примеров:
$ x = "abcdef";
$ x = ~ / abc (? {print "Привет, мама!";}) def /; # Спички,
# выводит сообщение "Привет, мама!"
$ x = ~ / aaa (? {print "Привет, мама!";}) def /; # не совпадает,
# нет "Привет, мама!"
Обратите особое внимание на следующий пример:
$ x = ~ / abc (? {print "Привет, мама!";}) ddd /; # не совпадает,
# нет "Привет, мама!"
# но почему нет?
На первый взгляд может показаться, что он не должен печататься, потому что, очевидно, "ddd" не
будет соответствовать целевой строке. Но посмотрите на этот пример:
$ x = ~ / abc (? {print "Привет, мама!";}) [dD] dd /; # не совпадает,
# но _выводит_ печать
Хм. Что здесь случилось? Если вы следовали инструкциям, то знаете, что приведенный выше шаблон
должен быть фактически (почти) таким же, как предыдущий; заключая "d" в символ
class не изменит то, что ему соответствует. Так почему же первый не печатается, а
второй делает?
Ответ кроется в оптимизации, которую делает движок регулярных выражений. В первом случае все
движок видит простые старые символы (кроме конструкции "? {}"). Это достаточно умно
чтобы понять, что строка 'ddd' не встречается в нашей целевой строке до того, как
прогоняя узор насквозь. Но во втором случае мы обманом заставили его думать, что
наш узор более сложный. Он смотрит, видит наш класс персонажа и решает
что ему нужно будет фактически запустить шаблон, чтобы определить, соответствует ли он, и
в процессе выполнения он попадает в оператор печати до того, как обнаруживает, что мы не
есть матч.
Чтобы подробнее узнать, как движок выполняет оптимизацию, см. Раздел «Прагмы и
отладка »ниже.
Больше удовольствия с "? {}":
$ x = ~ / (? {print "Привет, мама!";}) /; # Спички,
# выводит сообщение "Привет, мама!"
$ x = ~ / (? {$ c = 1;}) (? {print "$ c";}) /; # Спички,
# выводит "1"
$ x = ~ / (? {$ c = 1;}) (? {print "$ ^ R";}) /; # Спички,
# выводит "1"
Волшебство, упомянутое в заголовке раздела, происходит, когда регулярное выражение возвращается в
процесс поиска совпадения. Если регулярное выражение возвращается к кодовому выражению и если
переменные, используемые внутри, локализованы с использованием "local", изменения в переменных
произведенные кодовым выражением отменяются! Таким образом, если бы мы хотели подсчитать, сколько раз
символ был сопоставлен внутри группы, мы могли бы использовать, например,
$ x = "аааа";
$ count = 0; # инициализировать счетчик 'a'
$ c = "боб"; # проверить, не засоряется ли $ c
$ x = ~ / (? {local $ c = 0;}) # инициализировать счетчик
(# совпадение 'a'
(? {local $ c = $ c + 1;}) # увеличить счетчик
) * # проделайте это сколько угодно раз,
aa # но совпадать с 'aa' в конце
(? {$ count = $ c;}) # копируем локальную переменную $ c в $ count
/Икс;
print "'a' count is $ count, \ $ c variable is '$ c' \ n";
Это печатает
'a' - 2, переменная $ c - 'bob'
Если мы заменим "(? {Local $ c = $ c + 1;})" на "(? {$ C = $ c + 1;})", переменная
изменения отменяется при возврате, и мы получаем
'a' - 4, переменная $ c - 'bob'
Обратите внимание, что отменяются только изменения локализованных переменных. Другие побочные эффекты кода
выполнение выражения является постоянным. Таким образом
$ x = "аааа";
$ x = ~ / (a (? {print "Yow \ n";})) * aa /;
производит
Yow
Yow
Yow
Yow
Результат $ ^ R автоматически локализуется, поэтому он будет вести себя правильно в присутствии
возврата.
В этом примере выражение кода в условном выражении используется для сопоставления определенной статьи либо
'the' по-английски или 'der | die | das' по-немецки:
$ lang = 'DE'; # используйте немецкий
...
$ text = "дас";
напечатать "совпадает \ n"
если $ text = ~ / (? (? {
$ lang eq 'EN'; # это английский язык?
})
| # если да, то сопоставьте 'the'
(der | die | das) # else, соответствует 'der | die | das'
)
/ xi;
Обратите внимание, что здесь используется синтаксис "(? (? {...}) yes-regexp | no-regexp)", а не
"(? ((? {...})) да-регулярное выражение | нет-регулярное выражение)". Другими словами, в случае кодового выражения мы
не нужны лишние круглые скобки вокруг условного оператора.
Если вы попытаетесь использовать выражения кода, в которых текст кода содержится в интерполированном
Perl может вас удивить, а не буквально появляться в шаблоне:
$ bar = 5;
$ pat = '(? {1})';
/ foo (? {$ bar}) bar /; # компилируется нормально, $ bar не интерполируется
/ foo (? {1}) $ bar /; # компилируется нормально, $ bar интерполирован
/ foo $ {pat} bar /; # ошибка компиляции!
$ pat = qr / (? {$ foo = 1}) /; # предварительно скомпилировать код regexp
/ foo $ {pat} bar /; # компилируется нормально
Если в регулярном выражении есть переменная, которая интерполирует кодовое выражение, Perl обрабатывает регулярное выражение как
ошибка. Однако если кодовое выражение предварительно скомпилировано в переменную, интерполяция будет
в порядке. Вопрос в том, почему это ошибка?
Причина в том, что интерполяция переменных и кодовые выражения вместе создают безопасность.
риск. Комбинация опасна, потому что многие программисты, пишущие поисковые системы
часто принимают вводимые пользователем данные и вставляют их прямо в регулярное выражение:
$ regexp = <>; # читать пользовательское регулярное выражение
$ chomp $ regexp; # избавляемся от возможной новой строки
$ text = ~ / $ regexp /; # ищем $ text для $ regexp
Если переменная $ regexp содержит кодовое выражение, пользователь может выполнить произвольное
Код Perl. Например, какой-нибудь шутник может искать «system ('rm -rf *');» стереть твой
файлы. В этом смысле сочетание интерполяции и кодовых выражений портит
регулярное выражение. Таким образом, по умолчанию с использованием как интерполяции, так и кодовых выражений в одном и том же регулярном выражении
не разрешено. Если вас не беспокоят злоумышленники, можно обойти
эту проверку безопасности, вызвав «use re 'eval'»:
используйте re 'eval'; # выбросить осторожность за дверь
$ bar = 5;
$ pat = '(? {1})';
/ foo $ {pat} bar /; # компилируется нормально
Другая форма выражения кода - это описания код выражение. Код шаблона
выражение похоже на выражение регулярного кода, за исключением того, что результат кода
оценка обрабатывается как регулярное выражение и сразу же сопоставляется. Простой пример
is
$ length = 5;
$ char = 'а';
$ x = 'ааааабб';
$ x = ~ / (?? {$ char x $ length}) / x; # совпадений, 5 из них
Этот последний пример содержит выражения как обычного, так и шаблонного кода. Он обнаруживает
имеет ли двоичная строка 1101010010001 ... интервал Фибоначчи 0,1,1,2,3,5, ...
1-е годы:
$ x = "1101010010001000001";
$ z0 = ''; $ z1 = '0'; # первоначальные условия
print "Это последовательность Фибоначчи \ n"
if $ x = ~ / ^ 1 # соответствует начальной "1"
(?:
((?? {$ z0})) # найти какой-нибудь '0'
1 #, а затем '1'
(? {$ z0 = $ z1; $ z1. = $ ^ N;})
) + # повторить по мере необходимости
$ # это все, что есть
/Икс;
printf "Наибольшая совпавшая последовательность была% d \ n", length ($ z1) -length ($ z0);
Помните, что для $ ^ N установлено значение, совпадающее с последней завершенной группой захвата. Этот
печать
Это последовательность Фибоначчи.
Наибольшая совпадающая последовательность была 5
Ха! Попробуйте это с пакетом регулярных выражений для вашего сада ...
Обратите внимание, что переменные $ z0 и $ z1 не заменяются при компиляции регулярного выражения, так как
происходит для обычных переменных вне кодового выражения. Скорее всего, весь блок кода
анализируется как код Perl, в то время как perl компилирует код, содержащий литерал
шаблон регулярного выражения.
Регулярное выражение без модификатора "// x" -
/ ^ 1 (?: ((?? {$ z0})) 1 (? {$ Z0 = $ z1; $ z1. = $ ^ N;})) + $ /
что показывает, что в частях кода все еще возможны пробелы. Тем не менее при работе
с кодом и условными выражениями расширенная форма регулярных выражений почти необходима в
создание и отладка регулярных выражений.
Откат контроль Глаголы
Perl 5.10 представил ряд управляющих команд, предназначенных для детального контроля над
процесс поиска с возвратом, напрямую влияя на механизм регулярного выражения и предоставляя
методы мониторинга. Поскольку все функции в этой группе являются экспериментальными и подлежат
изменение или удаление в будущей версии Perl, заинтересованный читатель может
«Специальные управляющие глаголы с возвратом» в perlre для подробного описания.
Ниже приведен только один пример, иллюстрирующий управляющий глагол "(* FAIL)", который может быть
сокращенно «(* F)». Если это будет вставлено в регулярное выражение, оно приведет к сбою, так же как
это было бы при некотором несоответствии между шаблоном и строкой. Обработка регулярного выражения
продолжается, как это было бы после любого "нормального" сбоя, так что, например, следующая позиция
в строке или другой альтернативный вариант. Поскольку несоответствие не сохраняет
захватывать группы или производить результаты, может потребоваться использовать это в сочетании с
встроенный код.
% count = ();
"supercalifragilisticexpialidocious" = ~
/ ([aeiou]) (? {$ count {$ 1} ++;}) (* FAIL) / i;
printf "% 3d '% s' \ n", $ count {$ _}, $ _ for (ключи сортировки% count);
Шаблон начинается с класса, соответствующего подмножеству букв. Всякий раз, когда это совпадает,
оператор типа "$ count {'a'} ++;" выполняется, увеличивая счетчик букв. потом
"(* FAIL)" выполняет то, что он говорит, и механизм регулярного выражения действует в соответствии с книгой: до тех пор, пока
поскольку конец строки не достигнут, позиция продвигается вперед перед поиском
другая гласная. Таким образом, совпадение или отсутствие совпадения не имеет значения, и механизм регулярного выражения продолжает работу.
пока не будет проверена вся струна. (Примечательно, что альтернативное решение
используя что-то вроде
$ count {lc ($ _)} ++ для split ('', "supercalifragilisticexpialidocious");
printf "% 3d '% s' \ n", $ count2 {$ _}, $ _ for (qw {aeiou});
значительно медленнее.)
Прагмы и отладка
Говоря об отладке, есть несколько прагм, доступных для управления и отладки регулярных выражений в
Perl. Мы уже встречали одну прагму в предыдущем разделе: «use re 'eval';»,
что позволяет интерполяции переменных и кодовым выражениям сосуществовать в регулярном выражении. Другой
прагмы
использовать re 'taint';
$ tainted = <>;
@parts = ($ tainted = ~ / (\ w +) \ s + (\ w +) /; # @parts теперь испорчены
Прагма "taint" заставляет любые подстроки из совпадения с испорченной переменной быть
испорченный тоже. Обычно это не так, поскольку регулярные выражения часто используются для извлечения
безопасные биты из испорченной переменной. Используйте "taint", когда вы не извлекаете безопасные биты, а
выполняют другую обработку. И прагмы "taint", и "eval" лексически
scoped, что означает, что они действуют только до конца блока, включающего
прагмы.
используйте re '/ m'; # или любые другие флаги
$ multiline_string = ~ / ^ foo /; # / м подразумевается
Прагма "re '/ flags" (введенная в Perl 5.14) включает данное регулярное выражение.
flags до конца лексической области видимости. См. "Режим / flags" в re для более подробной информации.
используйте re 'отладка';
/^(.*)$/s; # вывод отладочной информации
используйте re 'debugcolor';
/^(.*)$/s; # выводить отладочную информацию в живом цвете
Глобальные прагмы debug и debugcolor позволяют получить подробную отладочную информацию о
компиляция и выполнение регулярных выражений. «цвет отладки» такой же, как отладка, за исключением отладки
информация отображается в цвете на терминалах, которые могут отображать цветовые последовательности termcap.
Вот пример вывода:
% perl -e 'использовать повторно «отладка»; "abc" = ~ / a * b + c /; '
Компиляция REx 'a * b + c'
размер 9 сначала на 1
1: STAR(4)
2: ТОЧНЫЙ (0)
4: ПЛЮС(7)
5: ТОЧНЫЙ (0)
7: ТОЧНО (9)
9: END(0)
плавающий 'bc' в 0..2147483647 (проверка плавающего) minlen 2
Угадывая начало матча, REx 'a * b + c' против 'abc' ...
Обнаружена плавающая substr 'bc' по смещению 1 ...
Угадано: совпадение по смещению 0
Сопоставление REx 'a * b + c' с 'abc'
Установка области EVAL, savestack = 3
0 <> | 1: ЗВЕЗДА
ТОЧНО может соответствовать 1 раз из 32767 ...
Установка области EVAL, savestack = 3
1 | 4: ПЛЮС
ТОЧНО может соответствовать 1 раз из 32767 ...
Установка области EVAL, savestack = 3
2 | 7: ТОЧНО
3 <> | 9: КОНЕЦ
Матч успешен!
Освобождение REx: 'a * b + c'
Если вы дошли до этого урока, вы, вероятно, догадались, в чем разница
части вывода отладки сообщают вам. Первая часть
Компиляция REx 'a * b + c'
размер 9 сначала на 1
1: STAR(4)
2: ТОЧНЫЙ (0)
4: ПЛЮС(7)
5: ТОЧНЫЙ (0)
7: ТОЧНО (9)
9: END(0)
описывает этап компиляции. STAR(4) означает, что в этом
case 'a', и если он совпадает, перейти к строке 4, т. е. ПЛЮС(7). Средние строки описывают некоторые
эвристика и оптимизация, выполненные перед матчем:
плавающий 'bc' в 0..2147483647 (проверка плавающего) minlen 2
Угадывая начало матча, REx 'a * b + c' против 'abc' ...
Обнаружена плавающая substr 'bc' по смещению 1 ...
Угадано: совпадение по смещению 0
Затем выполняется сопоставление, а остальные строки описывают процесс:
Сопоставление REx 'a * b + c' с 'abc'
Установка области EVAL, savestack = 3
0 <> | 1: ЗВЕЗДА
ТОЧНО может соответствовать 1 раз из 32767 ...
Установка области EVAL, savestack = 3
1 | 4: ПЛЮС
ТОЧНО может соответствовать 1 раз из 32767 ...
Установка области EVAL, savestack = 3
2 | 7: ТОЧНО
3 <> | 9: КОНЕЦ
Матч успешен!
Освобождение REx: 'a * b + c'
Каждый шаг имеет вид "n ", с участием " "совпала часть строки и" "
деталь еще не подобрана. "| 1: STAR" означает, что Perl находится в строке номер 1 в
список компиляции выше. См. «Отладка регулярных выражений» в perldebguts для получения дополнительной информации.
подробно.
Альтернативный метод отладки регулярных выражений - встраивание операторов print в
регулярное выражение. Это дает подробный отчет о возврате в чередовании:
"that this" = ~ m @ (? {print "Начать с позиции", pos, "\ n";})
t (? {print "t1 \ n";})
h (? {print "h1 \ n";})
я (? {print "i1 \ n";})
s (? {print "s1 \ n";})
|
t (? {print "t2 \ n";})
h (? {print "h2 \ n";})
a (? {print "a2 \ n";})
t (? {print "t2 \ n";})
(? {print "Done at position", pos, "\ n";})
@Икс;
печать
Начать с позиции 0
t1
h1
t2
h2
a2
t2
Выполнено на позиции 4
Используйте perlretut онлайн с помощью сервисов onworks.net