perlre
СОДЕРЖАНИЕ
- ИМЯ
- ОПИСАНИЕ
- Основы
- Модификаторы
- Регулярные выражения
- Обрамление метасимволов
- Расширенные шаблоны
- Обратный откат
- Выполнения сценариев
- Специальные глаголы управления обратным откатом
- Предупреждение о \1 вместо $1
- Повторные шаблоны, сопоставляющие подстроку нулевой длины
- Объединение частей регулярных выражений
- Создание собственных движков регулярных выражений
- Частота выполнения встроенного кода
- Поддержка PCRE/Python
- ОШИБКИ
- СМОТРИТЕ ТАКЖЕ
ИМЯ
perlre - Регулярные выражения Perl
ОПИСАНИЕ
На этой странице описана синтаксис регулярных выражений в Perl.
Если вы не работали с регулярными выражениями ранее, доступен учебный вводный курс в perlretut. Если вы знаете немного о них, доступен краткий вводный курс в perlrequick.
За исключением раздела "Основы", на этой странице предполагается, что вы знакомы с основами регулярных выражений, такими как, что такое "шаблон", как он выглядит и как он в основном используется. Для справки о том, как они используются, а также различных примеров одного и того же, см. обсуждения m//, s///, qr// и "??" в "Операторы цитирования регулярных выражений" в perlop.
В версии v5.22, use re 'strict' применяет более строгие правила, чем обычно, при компиляции шаблонов регулярных выражений. Он может обнаруживать вещи, которые, хотя и законны, могут не соответствовать вашему замыслу.
Основы
Регулярные выражения — это строки со своим особым синтаксисом и значением, описанными в этом документе и дополнительных документах, на которые он ссылается. Эти строки называются «шаблонами». Шаблоны используются для определения, содержит ли другая строка, называемая «целью», указанные в шаблоне характеристики. Мы называем это "сопоставлением" строки-цели с шаблоном. Обычно сопоставление выполняется с использованием строки-цели в качестве первого операнда и шаблона во втором, с помощью одного из двух бинарных операторов =~ и !~, перечисленных в "Операторы связи" в perlop; а шаблон был преобразован из обычной строки одним из операторов в "Операторы цитирования регулярных выражений" в perlop, например:
$foo =~ m/abc/ Это истинно тогда и только тогда, когда строка в переменной $foo содержит последовательность символов "a", "b" и затем "c". (Оператор =~ m, или оператор сопоставления, описан в "m/PATTERN/msixpodualngc" в perlop.)
Шаблоны, которые еще не хранятся в какой-либо переменной, должны быть ограничены символами-разделителями с обеих сторон. Часто, как в примере выше, используются обратные слэши, и типичный способ записи шаблона в документации — с этими слэшами. В большинстве случаев разделитель одинаков спереди и сзади, но есть несколько случаев, где символ выглядит как отражение, где открытый символ — начальный разделитель, а закрытый — конечный разделитель, например
$foo =~ m<abc> В большинстве случаев шаблон вычисляется в контексте двойных кавычек, но можно выбрать разделители, чтобы принудительно использовать одинарные кавычки, как
$foo =~ m'abc' Если шаблон содержит свой разделитель внутри, этот разделитель должен быть экранирован. Предварительный разделитель обратной косой чертой (например, "/foo\/bar/") выполняет эту задачу.
Любой отдельный символ в шаблоне соответствует этому же символу в строке-цели, если этот символ не является метасимволом со специальным значением, описанным в данном документе. Последовательность неметасимволов соответствует той же последовательности в строке-цели, как мы видели выше с m/abc/.
Только несколько символов (все они являются символами пунктуации ASCII) являются метасимволами. Наиболее часто используемый — точка ".", которая обычно соответствует практически любому символу (включая саму точку).
Вы можете заставить символы, которые обычно действуют как метасимволы, интерпретироваться буквально, предварив их обратной косой чертой "\", так же как разделитель шаблона должен быть экранирован, если он также встречается внутри шаблона. Таким образом, "\." соответствует только символу точки, "." вместо его обычного значения. Это означает, что обратная косая черта также является метасимволом, поэтому "\\" соответствует одному "\". А последовательность, содержащая экранированный метасимвол, соответствует той же последовательности (но без экранирования) в строке-цели. Таким образом, шаблон /blur\\fl/ соответствовал бы любой строке-цели, содержащей последовательность "blur\fl".
Метасимвол "|" используется для соответствия одному из двух. Например
$foo =~ m/this|that/ ИСТИННО тогда и только тогда, когда $foo содержит либо последовательность "this", либо последовательность "that". Как и все метасимволы, предваряя "|" обратной косой чертой, вы получаете соответствие простому символу пунктуации; в данном случае, вертикальной черте.
$foo =~ m/this\|that/ ИСТИННО тогда и только тогда, когда $foo содержит последовательность "this|that".
Вы не ограничены только одним "|".
$foo =~ m/fee|fie|foe|fum/ ИСТИННО тогда и только тогда, когда $foo содержит любую из этих 4 последовательностей из детской сказки "Jack and the Beanstalk".
Как вы можете видеть, "|" связывается слабее, чем последовательность обычных символов. Мы можем переопределить это, используя метасимволы группирования, круглые скобки "(" и ")".
$foo =~ m/th(is|at) thing/ ИСТИННО тогда и только тогда, когда $foo содержит либо последовательность "this thing", либо последовательность "that thing". Части строки, соответствующие частям шаблона, заключенные в круглые скобки, обычно предоставляются отдельно для последующего использования в шаблоне, замене или программе. Это называется «захватом», и оно может усложняться. См. "Группы захвата".
Первый вариант включает все от последнего разделителя шаблона ("(", "(?:" (описано позже), и т.д. или от начала шаблона) до первого "|", а последний вариант содержит все от последнего "|" до следующего закрывающего разделителя шаблона. Именно поэтому принято заключать альтернативы в круглые скобки: чтобы свести к минимуму путаницу относительно того, где они начинаются и заканчиваются.
Альтернативы проверяются слева направо, поэтому первой найденной альтернативой, для которой соответствует всё выражение, является та, которая выбирается. Это означает, что альтернативы не обязательно жадные. Например, при сопоставлении foo|foot со строкой "barefoot", будет соответствовать только часть "foo", так как эта альтернатива проверяется первой и успешно соответствует строке-цели. (Это может показаться неважным, но это важно, когда вы захватываете сопоставленный текст с помощью круглых скобок.)
Помимо отмены специального значения метасимвола, предшествующая обратная косая черта меняет некоторые символы букв и цифр от соответствия только самим себе до наличия специального значения. Они называются "экранированными последовательностями", и все они описаны в perlrebackslash. Последовательность обратной косой черты (буквы или цифры), которая в данный момент не имеет специального значения для Perl, выведет предупреждение, если включены предупреждения, поскольку они зарезервированы для возможного будущего использования.
Одна из таких последовательностей — \b, которая соответствует границе какого-либо типа. \b{wb} и несколько других предоставляют специализированные типы границ. (Они подробно описаны начиная с "\b{}, \b, \B{}, \B" в perlrebackslash.) Обратите внимание, что они не соответствуют символам, но нулевой ширине между символами. Они являются примером утверждения нулевой ширины. Рассмотрим снова,
$foo =~ m/fee|fie|foe|fum/ Это истинно, если помимо этих 4 слов, в $foo присутствуют любые из последовательностей "feed", "field", "Defoe", "fume", и многие другие. С помощью продуманного использования \b (или лучше (поскольку оно предназначено для обработки естественного языка) \b{wb}), мы можем убедиться, что будут соответствовать только слова великана:
$foo =~ m/\b(fee|fie|foe|fum)\b/
$foo =~ m/\b{wb}(fee|fie|foe|fum)\b{wb}/ На последнем примере показано, что символы "{" и "}" являются метасимволами.
Другое применение последовательностей с экранированием — указание символов, которые нельзя (или нежелательно) вводить буквально. Подробное описание этих символов приведено в "Character Escapes" в perlrebackslash, но в следующих трёх абзацах кратко описаны некоторые из них.
Различные управляющие символы могут быть записаны в стиле языка C: "\n" соответствует новой строке, "\t" — табуляции, "\r" — возврату каретки, "\f" — подаче страницы, и т. д.
Более обобщенно, \nnn, где nnn — строка из трёх восьмеричных цифр, соответствует символу с кодовым значением nnn. Вы легко можете столкнуться с проблемами, если не используете ровно три цифры. Поэтому всегда используйте три цифры, или, начиная с Perl 5.14, вы можете использовать \o{...} для указания любого количества восьмеричных цифр.
Аналогично, \xnn, где nn — шестнадцатеричные цифры, соответствует символу с порядковым номером nn. Опять же, использование не ровно двух цифр может привести к ошибкам, но вы можете использовать \x{...} для указания любого количества шестнадцатеричных цифр.
Помимо того, что "." является метасимволом, он также является примером «класса символов», то есть может соответствовать любому одиночному символу из заданного набора. В данном случае, набор включает практически все возможные символы. Perl предопределяет несколько классов символов помимо "."; о них есть отдельная справочная страница — perlrecharclass.
Вы можете определять свои собственные пользовательские классы символов, размещая в нужном месте(ах) шаблона список всех символов, которые вы хотите включить в набор. Это делается путем заключения списка в [] квадратные скобки. В точности эти классы называются «классами символов в квадратных скобках», но часто слово «в квадратных скобках» опускают. (Обычно это не приводит к путанице.) Это означает, что "[" символ — это ещё один метасимвол. Он сам по себе ничего не соответствует; он используется только для того, чтобы указать Perl, что то, что следует за ним, — это класс символов в квадратных скобках. Если вам нужно сопоставить литеру открывающую квадратную скобку, необходимо экранировать её, как "\[". Соответствующий "]" тоже метасимвол; он ничего сам по себе не соответствует, но просто отмечает конец вашего пользовательского класса для Perl. Это пример «иногда метасимвола». Это не метасимвол, если нет соответствующего "[", и соответствует своей литере:
print "]" =~ /]/; # prints 1 Список символов внутри класса символов задаёт набор символов, соответствующих классу. "[abc]" соответствует одному из символов "a", "b" или "c". Но если первый символ после "[" — "^", класс вместо этого соответствует любому символу, который не входит в список. Внутри списка символ "-" задаёт диапазон символов, так что a-z представляет все символы от "a" до "z" включительно. Если вы хотите, чтобы "-" или "]" сами были членами класса, поместите их в начале списка (возможно, после "^") или экранируйте их обратной косой чертой. "-" также интерпретируется буквально, когда он находится в конце списка, непосредственно перед закрывающей "]" . (Следующие все задают один и тот же класс из трёх символов: [-az], [az-], и [a\-z]. Все они отличаются от [a-z], который задаёт класс, содержащий двадцать шесть символов, даже на наборах символов, основанных на EBCDIC.)
Есть много другого, касающегося классов символов в квадратных скобках; полные подробности см. в "Bracketed Character Classes" в perlrecharclass.
Метасимволы
"Основы" представили некоторые метасимволы. Этот раздел предоставляет их все. Большинство из них имеют то же значение, что и в команде egrep.
Только "\" всегда является метасимволом. Остальные являются метасимволами только иногда. В следующих таблицах перечислены все метасимволы, кратко описано их использование и контексты, в которых они являются метасимволами. Вне этих контекстов или если они опережаются "\", они соответствуют соответствующему знаку препинания. В некоторых случаях их значение зависит от различных модификаторов шаблонов, которые изменяют стандартное поведение. См. "Модификаторы".
PURPOSE WHERE
\ Escape the next character Always, except when
escaped by another \
^ Match the beginning of the string Not in []
(or line, if /m is used)
^ Complement the [] class At the beginning of []
. Match any single character except newline Not in []
(under /s, includes newline)
$ Match the end of the string Not in [], but can
(or before newline at the end of the mean interpolate a
string; or before any newline if /m is scalar
used)
| Alternation Not in []
() Grouping Not in []
[ Start Bracketed Character class Not in []
] End Bracketed Character class Only in [], and
not first
* Matches the preceding element 0 or more Not in []
times
+ Matches the preceding element 1 or more Not in []
times
? Matches the preceding element 0 or 1 Not in []
times
{ Starts a sequence that gives number(s) Not in []
of times the preceding element can be
matched
{ when following certain escape sequences
starts a modifier to the meaning of the
sequence
} End sequence started by {
- Indicates a range Only in [] interior
# Beginning of comment, extends to line end Only with /x modifier Обратите внимание, что большинство метасимволов теряют своё особое значение, когда они встречаются в классе символов в квадратных скобках, за исключением "^", который имеет другое значение, когда он находится в начале такого класса. И "-" и "]" являются метасимволами только в ограниченных позициях внутри классов символов в квадратных скобках; в то время как "}" является метасимволом только при закрытии специальной конструкции, начатой с "{".
В контексте двойных кавычек, как это обычно бывает, вам нужно быть осторожными с "$" и нематасимволом "@". Они могут интерполировать переменные, что может или не может быть тем, что вы имели в виду.
Эти правила были разработаны для компактности выражений, а не для удобочитаемости и поддерживаемости. Модификаторы шаблонов "/x и /xx" позволяют вставлять пробелы для улучшения удобочитаемости. И использование re 'strict' добавляет дополнительную проверку для обнаружения некоторых опечаток, которые могут безмолвно скомпилироваться во что-то непреднамеренное.
По умолчанию символ "^" гарантированно соответствует только началу строки, символ "$" — только концу (или перед новой строкой в конце), и Perl производит определенные оптимизации, исходя из предположения, что строка содержит только одну строку. Вложенные новые строки не будут соответствовать "^" или "$". Однако вы, возможно, захотите обработать строку как буфер с несколькими строками, так что "^" будет соответствовать после любой новой строки внутри строки (за исключением случая, когда новая строка является последним символом в строке), а "$" — перед любой новой строкой. За счёт немного большего объёма работы, это можно сделать, используя модификатор "/m" в операторе поиска по шаблону. (Старые программы делали это, устанавливая $*, но этот параметр был удалён в perl 5.10.)
Для упрощения подстановок в нескольких строках символ "." никогда не соответствует новой строке, если вы не используете модификатор /s, который фактически заставляет Perl рассматривать строку как одну строку — даже если это не так.
Модификаторы
Обзор
Поведение сопоставления по умолчанию можно изменить, используя различные модификаторы. Модификаторы, относящиеся к интерпретации шаблона, перечислены ниже. Модификаторы, изменяющие способ использования шаблона Perl, описаны в "Regexp Quote-Like Operators" в perlop и "Подробности обработки цитируемых конструкций" в perlop.
-
m -
Обрабатывайте строку, с которой производится сопоставление, как многострочную. То есть, измените
"^"и"$"с сопоставления начала первой строки и конца последней строки на сопоставление начала и конца каждой строки в строке. -
s -
Обрабатывайте строку как однострочную. То есть, измените
"."на сопоставление любого символа, даже символа новой строки, с которым обычно оно не совпадало.Используемые вместе, как
/ms, они позволяют"."сопоставлять любой символ, при этом позволяя"^"и"$"сопоставлять, соответственно, сразу после и сразу перед символами новой строки в строке. -
i -
Выполняйте сопоставление шаблона без учета регистра. Например, "A" будет сопоставляться с "a" в
/i.Если правила сопоставления по локали действуют, то таблица соответствия регистров берется из текущей локали для кодовых точек меньше 255 и из правил Unicode для кодовых точек большего размера. Однако, совпадения, которые пересекают границу правил Unicode/не-Unicode (ords 255/256), не будут иметь успеха, если локаль не является UTF-8. См. perllocale.
Существует ряд символов Unicode, которые сопоставляются с последовательностью нескольких символов в
/i. Например,LATIN SMALL LIGATURE FIдолжно сопоставляться с последовательностьюfi. Perl в настоящее время не может этого сделать, когда несколько символов находятся в шаблоне и разделены группами, или когда один или несколько из них колифицированы."\N{LATIN SMALL LIGATURE FI}" =~ /fi/i; # Matches "\N{LATIN SMALL LIGATURE FI}" =~ /[fi][fi]/i; # Doesn't match! "\N{LATIN SMALL LIGATURE FI}" =~ /fi*/i; # Doesn't match! # The below doesn't match, and it isn't clear what $1 and $2 would # be even if it did!! "\N{LATIN SMALL LIGATURE FI}" =~ /(f)(i)/i; # Doesn't match!Perl не сопоставляет несколько символов в классе символов в квадратных скобках, если символ, который сопоставляется им, не указан явно, и не сопоставляет их вообще, если класс символов инвертирован, что в противном случае могло бы быть очень запутанно. См. "Классы символов в квадратных скобках" в perlrecharclass и "Отрицание" в perlrecharclass.
-
xиxx -
Улучшите читабельность вашего шаблона, разрешив пробелы и комментарии. Подробности в "/x и /xx"
-
p -
Сохраните сопоставленную строку таким образом, чтобы
${^PREMATCH},${^MATCH}, и${^POSTMATCH}были доступны для использования после сопоставления.В Perl 5.20 и выше это игнорируется. Из-за новой механизма копирования при записи
${^PREMATCH},${^MATCH}, и${^POSTMATCH}будут доступны после сопоставления независимо от модификатора. -
a,d,l, иu -
Эти модификаторы, все новые в версии 5.14, влияют на то, какие правила набора символов (Unicode и т. д.) используются, как описано ниже в "Модификаторы набора символов".
-
n -
Предотвратите захват метасимволов группирования
(). Этот модификатор, новый в версии 5.22, остановит$1,$2, и т. д. от заполнения."hello" =~ /(hi|hello)/; # $1 is "hello" "hello" =~ /(hi|hello)/n; # $1 is undefЭто эквивалентно добавлению
?:в начало каждой группы захвата:"hello" =~ /(?:hi|hello)/; # $1 is undef/nможет быть отрицано на основе каждой группы. В качестве альтернативы, могут по-прежнему использоваться именованные захваты."hello" =~ /(?-n:(hi|hello))/n; # $1 is "hello" "hello" =~ /(?<greet>hi|hello)/n; # $1 is "hello", $+{greet} is # "hello" - Другие модификаторы
-
Есть ряд флагов, которые можно найти в конце конструкций регулярных выражений, которые не являются общими флагами регулярных выражений, но применяются к выполняемой операции, например, сопоставлению или замене (
m//илиs///соответственно).Флаги, описанные далее в "Использование регулярных выражений в Perl" в perlretut:
c - keep the current position during repeated matching g - globally match the pattern repeatedly in the stringМодификаторы, специфичные для замены, описанные в "s/PATTERN/REPLACEMENT/msixpodualngcer" в perlop:
e - evaluate the right-hand side as an expression ee - evaluate the right side as a string then eval the result o - pretend to optimize your code, but actually introduce bugs r - perform non-destructive substitution and return the new value
Модификаторы регулярных выражений обычно записываются в документации, например, «модификатор /x», даже если разделитель в данном случае не является косой чертой. Модификаторы /imnsxadlup также могут быть встроены в само регулярное выражение с использованием конструкции (?...) , см. "Расширенные шаблоны" ниже.
Подробности по некоторым модификаторам
Некоторые модификаторы требуют более подробного объяснения, чем приведенное в "Обзор" выше.
/x и /xx
Один /x сообщает парсеру регулярных выражений игнорировать большинство пробелов, которые не являются обрамленными обратным слэшем или не находятся внутри класса символов в квадратных скобках. Вы можете использовать это, чтобы разбить ваше регулярное выражение на более читаемые части. Кроме того, символ "#" обрабатывается как метасимвол, вводящий комментарий, который проходит до закрывающего разделителя шаблона или до конца текущей строки, если шаблон переходит на следующую строку. Следовательно, это очень похоже на обычный комментарий кода Perl. (Вы можете включить закрывающий разделитель в комментарий только в том случае, если вы предваряете его обратным слэшем, поэтому будьте осторожны!)
Использование /x означает, что если вы хотите реальные пробелы или "#" символы в шаблоне (вне класса символов в квадратных скобках, на который /x не влияет), то вам нужно будет либо экранировать их (с помощью обратных слэшей или \Q...\E ), либо закодировать их с помощью восьмеричных, шестнадцатеричных или \N{} экранов. Неэффективно пытаться продолжить комментарий на следующую строку, экранируя \n с обратным слэшем или \Q.
Вы можете использовать (?#text) для создания комментария, который заканчивается раньше, чем конец текущей строки, но text также не может содержать закрывающий разделитель, если он не экранирован обратным слэшем.
Распространённая ошибка — забыть, что "#" символы начинают комментарий при /x и не сопоставляются буквально. Просто помните об этом, пытаясь понять, почему определенный /x шаблон не работает так, как ожидалось.
Начиная с Perl v5.26, если модификатор имеет второй "x" внутри, он делает все, что делает одиночный /x, но дополнительно неэкранированные символы ПРОБЕЛ и ТАБУ внутри классов символов в квадратных скобках также обычно игнорируются и, следовательно, могут быть добавлены для повышения читабельности классов.
/ [d-e g-i 3-7]/xx
/[ ! @ " # $ % ^ & * () = ? <> ' ]/xx может быть легче понять, чем сжатые эквиваленты
/[d-eg-i3-7]/
/[!@"#$%^&*()=?<>']/ В совокупности эти особенности в значительной степени повышают читаемость регулярных выражений Perl. Вот пример:
# Delete (most) C comments.
$program =~ s {
/\* # Match the opening delimiter.
.*? # Match a minimal number of characters.
\*/ # Match the closing delimiter.
} []gsx; Обратите внимание, что всё внутри \Q...\E не подвержено влиянию /x. И обратите внимание, что /x не влияет на интерпретацию пробелов внутри одной многосимвольной конструкции. Например, в \x{...}, независимо от модификатора /x, пробелов быть не может. То же самое для квантификатора, такого как {3} или {5,}. Аналогично, (?:...) не может содержать пробел между "(", "?", и ":". Внутри любых разделителей такой конструкции разрешённые пробелы не затрагиваются /x, и зависят от конструкции. Например, \x{...} не может содержать пробелов, потому что шестнадцатеричные числа не содержат пробелов. Однако, свойства Unicode могут содержать пробелы, поэтому в \p{...} могут быть пробелы, соответствующие правилам Unicode, см. "Свойства, доступные через \p{} и \P{}" в perluniprops.
Множество символов, которые считаются пробелами, — это те, что Unicode называет "Пробелами шаблона", а именно:
U+0009 CHARACTER TABULATION
U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0020 SPACE
U+0085 NEXT LINE
U+200E LEFT-TO-RIGHT MARK
U+200F RIGHT-TO-LEFT MARK
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR Модификаторы набора символов
/d, /u, /a, и /l, доступные начиная с версии 5.14, называются модификаторами набора символов; они влияют на правила набора символов, используемые для регулярного выражения.
Модификаторы /d, /u, и /l вряд ли будут для вас полезны, и поэтому вам не нужно сильно беспокоиться об них. Они существуют для внутреннего использования Perl, чтобы сложные структуры данных регулярных выражений могли быть автоматически сериализованы и позже точно восстановлены, включая все их нюансы. Но, поскольку Perl не может хранить секреты, и могут быть редкие случаи, когда они полезны, они документированы здесь.
Модификатор /a, с другой стороны, может быть полезен. Его цель — позволить коду, который в основном работает с данными ASCII, не беспокоиться о Unicode.
Вкратце, /l устанавливает набор символов в соответствии с текущей локалью во время выполнения сопоставления шаблона.
/u устанавливает набор символов в Unicode.
/a также устанавливает набор символов в Unicode, НО добавляет несколько ограничений для безопасного сопоставления ASCII.
/d — это старое, проблемное, поведение набора символов по умолчанию до версии 5.14. Его единственное применение — принудительно использовать это старое поведение.
В любой момент времени действует ровно один из этих модификаторов. Их существование позволяет Perl сохранять первоначальное скомпилированное поведение регулярного выражения, независимо от правил, действующих при его фактическом выполнении. И если оно вставлено в большее регулярное выражение, первоначальные правила продолжают применяться к нему и не влияют на другие части.
Модификаторы /l и /u автоматически выбираются для регулярных выражений, скомпилированных в рамках различных прагм, и мы рекомендуем в общем случае использовать эти прагмы вместо явного указания этих модификаторов. Во-первых, модификаторы влияют только на сопоставление шаблонов и не распространяются даже на любые замены, тогда как использование прагм даёт согласованные результаты для всех соответствующих операций в пределах их области действия. Например,
s/foo/\Ubar/il будет сопоставлять "foo" с использованием правил локали для сопоставления без учета регистра, но /l не влияет на то, как работает \U. Скорее всего, вы хотите, чтобы оба они использовали правила локали. Для этого скомпилируйте регулярное выражение в рамках use locale. Это и подразумевает добавление /l, и применение правил локали к \U. Урок состоит в том, чтобы use locale, а не /l явно.
Аналогично, было бы лучше использовать use feature 'unicode_strings' вместо,
s/foo/\Lbar/iu чтобы получить правила Unicode, так как \L в первом (но не обязательно во втором) случае также будут использовать правила Unicode.
Более подробные сведения о каждом из модификаторов приведены ниже. Вероятнее всего, вам не нужно знать эти подробности для /l, /u, и /d, и вы можете перейти сразу к /a.
/l
означает использование правил текущего языка (см. perllocale) при сопоставлении шаблонов. Например, \w будет соответствовать символам «слова» этого языка, а "/i" регистронезависимое сопоставление будет соответствовать правилам преобразования регистра данного языка. Используемый язык будет тем, что действует в момент выполнения сопоставления шаблона. Это может отличаться от языка, установленного во время компиляции, и может отличаться от одного сопоставления к другому, если вызов функции setlocale() был выполнен между этими сопоставлениями.
До версии 5.20 Perl не поддерживал языки с многобайтовыми кодировками. Начиная с версии 5.20, поддерживаются языки с кодировкой UTF-8. Другие языки с многобайтовой кодировкой вряд ли будут поддерживаться. Однако во всех языках могут быть символы с кодовыми точками выше 255, и они всегда будут обрабатываться как Unicode независимо от того, какой язык используется.
Согласно правилам Unicode, существует несколько регистронезависимых сопоставлений, которые пересекают границу 255/256. За исключением языков с кодировкой UTF-8 в Perl версии 5.20 и более поздних версиях, они запрещены в /l. Например, 0xFF (на платформах ASCII) не регистронезависимо сопоставляется с символом в 0x178, LATIN CAPITAL LETTER Y WITH DIAERESIS, потому что 0xFF может не быть LATIN SMALL LETTER Y WITH DIAERESIS в текущем языке, и Perl не может знать, существует ли этот символ в языке, а тем более, какой у него код.
В языке с кодировкой UTF-8 в Perl версии 5.20 и более поздних версиях единственное заметное различие между языком и без него в регулярных выражениях должно заключаться в заражении (см. perlsec).
Этот модификатор может быть задан по умолчанию с помощью use locale, но см. "Какой модификатор набора символов действует?".
/u
означает использование правил Unicode при сопоставлении шаблонов. На платформах ASCII это означает, что кодовые точки от 128 до 255 принимают свои значения Latin-1 (ISO-8859-1) (которые совпадают со значениями Unicode). (В противном случае Perl считает их значения неопределёнными.) Таким образом, при этом модификаторе платформа ASCII фактически становится платформой Unicode; следовательно, например, \w будет соответствовать любому из более чем 100 000 символов «слова» в Unicode.
В отличие от большинства языков, которые специфичны для пары язык-страна, Unicode классифицирует все символы, которые являются буквами где-либо в мире, как \w. Например, ваш язык может не считать LATIN SMALL LETTER ETH буквой (если вы не говорите по-исландски), но Unicode считает. Аналогично, все символы, которые являются десятичными цифрами где-либо в мире, будут соответствовать \d; это сотни, а не 10 возможных совпадений. И некоторые из этих цифр выглядят как некоторые из 10 ASCII-цифр, но обозначают другое число, поэтому человек может легко подумать, что число имеет другое значение, чем оно есть на самом деле. Например, BENGALI DIGIT FOUR (U+09EA) очень похож на ASCII DIGIT EIGHT (U+0038), а LEPCHA DIGIT SIX (U+1C46) очень похож на ASCII DIGIT FIVE (U+0035). И, \d+, может соответствовать строкам цифр, которые являются смесью из разных письменностей, что создаёт проблему безопасности. Например, мошеннический сайт может отобразить цену чего-либо с помощью U+1C46, и пользователю может показаться, что что-то стоит 500 единиц, но на самом деле оно стоит 600. Браузер, который контролирует выполнение сценариев ("Выполнение сценариев"), предотвратит такое мошенническое отображение. "num()" в Unicode::UCD также можно использовать для решения этой проблемы. Или можно использовать модификатор /a для принудительного соответствия \d только ASCII-цифрам от 0 до 9.
Кроме того, при этом модификаторе регистронезависимое сопоставление работает со всем набором символов Unicode. Например, KELVIN SIGN соответствует буквам «k» и «K»; и LATIN SMALL LIGATURE FF соответствует последовательности "ff", что, если вы к этому не готовы, может заставить это выглядеть как шестнадцатеричная константа, представляя ещё одну потенциальную проблему безопасности. Подробное обсуждение проблем безопасности Unicode см. в http://unicode.org/reports/tr36.
Этот модификатор может быть задан по умолчанию с помощью use feature 'unicode_strings, use locale ':not_characters', или use 5.012 (или выше), но см. "Какой модификатор набора символов действует?".
/d
Этот модификатор означает использование «стандартных» собственных правил платформы, за исключением случаев, когда необходимо использовать правила Unicode, как показано ниже:
-
целевая строка закодирована в UTF-8; или
-
шаблон закодирован в UTF-8; или
-
в шаблоне явно упоминается кодовая точка, превышающая 255 (скажем, с помощью
\x{100}); или -
шаблон использует имя Unicode (
\N{...}); или -
шаблон использует свойство Unicode (
\p{...}или\P{...}); или -
шаблон использует разрыв Unicode (
\b{...}или\B{...}); или -
шаблон использует "
(?[ ])" -
шаблон использует
(*script_run: ...)
Ещё одним мнемоническим обозначением для этого модификатора является «Зависит», так как фактически используемые правила зависят от различных факторов, и в результате вы можете получить неожиданные результаты. См. "Ошибка Unicode" в perlunicode. Ошибка Unicode стала довольно печально известной, что привело к ещё одному (без ругательств) названию для этого модификатора — «Ненадёжный».
Если шаблон или строка не закодированы в UTF-8, только символы ASCII могут позитивно сопоставляться.
Вот несколько примеров того, как это работает на платформе ASCII:
$str = "\xDF"; # $str is not in UTF-8 format.
$str =~ /^\w/; # No match, as $str isn't in UTF-8 format.
$str .= "\x{0e0b}"; # Now $str is in UTF-8 format.
$str =~ /^\w/; # Match! $str is now in UTF-8 format.
chop $str;
$str =~ /^\w/; # Still a match! $str remains in UTF-8 format. Этот модификатор автоматически выбирается по умолчанию, когда ни один другой не выбран, поэтому ещё одно название для него — «По умолчанию».
Из-за неожиданного поведения, связанного с этим модификатором, вам, вероятно, следует использовать его только явно для сохранения странных обратных совместимостей.
/a (и /aa)
Этот модификатор означает ограничение ASCII (или безопасный ASCII). Этот модификатор можно удваивать, чтобы усилить его действие.
Когда он появляется один раз, он заставляет последовательности \d, \s, \w, и классы символов Posix сопоставляться только в диапазоне ASCII. Таким образом, они возвращаются к своим значениям до версии 5.6, до Unicode. В /a, \d всегда означает точно цифры от "0" до "9"; \s означает пять символов [ \f\n\r\t], и начиная с Perl версии 5.18, вертикальную вкладку; \w означает 63 символа [A-Za-z0-9_]; и аналогично все классы Posix, такие как [[:print:]] соответствуют только соответствующим символам диапазона ASCII.
Этот модификатор полезен для людей, которые случайно используют Unicode и не хотят быть обременёнными его сложностями и проблемами безопасности.
С /a, можно написать \d с уверенностью, что он будет соответствовать только символам ASCII, и если возникнет необходимость сопоставить символы за пределами ASCII, можно использовать \p{Digit} (или \p{Word} для \w). Существуют аналогичные \p{...} конструкции, которые могут сопоставлять символы за пределами ASCII, как пробелы (см. "Whitespace" в perlrecharclass), и классы Posix (см. "POSIX Character Classes" в perlrecharclass). Таким образом, этот модификатор не означает, что вы не можете использовать Unicode, это означает, что для получения соответствия Unicode вы должны явно использовать конструкцию (\p{}, \P{}) которая указывает на Unicode.
Как можно было ожидать, этот модификатор заставляет, например, \D означать то же самое, что и [^0-9]; на самом деле, все символы вне ASCII соответствуют \D, \S, и \W. \b всё ещё означает соответствие границе между \w и \W, используя определения /a (аналогично для \B).
В противном случае, /a ведет себя как модификатор /u, в том смысле, что регистронезависимое сопоставление использует правила Unicode; например, «k» будет соответствовать Unicode \N{KELVIN SIGN} при регистронезависимом сопоставлении /i, и кодовые точки в диапазоне Latin1, выше ASCII будут использовать правила Unicode в отношении регистронезависимого сопоставления.
Чтобы запретить соответствие ASCII/вне ASCII (например, «k» с \N{KELVIN SIGN}), укажите "a" дважды, например, /aai или /aia. (Первое вхождение "a" ограничивает \d, и так далее, а второе вхождение добавляет ограничения /i.) Но имейте в виду, что кодовые точки вне диапазона ASCII будут использовать правила Unicode для /i сопоставления, так что модификатор на самом деле не ограничивает всё только ASCII; он просто запрещает смешивание ASCII и вне ASCII.
Подводя итог, этот модификатор предоставляет защиту для приложений, которые не хотят быть подвержены всему Unicode. Указание его дважды даёт дополнительную защиту.
Этот модификатор может быть установлен по умолчанию с помощью use re '/a' или use re '/aa'. Если вы это сделаете, у вас может возникнуть случай, когда нужно использовать модификатор /u явно, если у вас есть несколько регулярных выражений, где вы хотите полные правила Unicode (но даже здесь лучше, если всё будет под функцией "unicode_strings", вместе с use re '/aa'). Также см. "Какой модификатор набора символов действует?".
Какой модификатор набора символов действует?
Какой из этих модификаторов действует в данный момент в регулярном выражении зависит от довольно сложной системы взаимодействий. Они разработаны таким образом, чтобы вы, как правило, не задумывались об этом, но этот раздел даёт подробную информацию. Как объяснено ниже в "Расширенные шаблоны", можно явно указать модификаторы, которые применяются только к частям регулярного выражения. Внутренние всегда имеют приоритет над любыми внешними, а применяемый ко всему выражению имеет приоритет над любыми из значений по умолчанию, описанных в оставшейся части этого раздела.
Прагма use re '/foo' может использоваться для установки модификаторов по умолчанию (включая эти) для регулярных выражений, скомпилированных в её области видимости. Эта прагма имеет приоритет над другими прагмами, перечисленными ниже, которые также изменяют значения по умолчанию.
В противном случае, use locale устанавливает значение по умолчанию для модификатора /l; а use feature 'unicode_strings, или use 5.012 (или выше) устанавливают значение по умолчанию на /u если они не находятся в том же объеме, что и use locale или use bytes. (use locale ':not_characters' также устанавливает значение по умолчанию на /u, переопределяя любое простое значение use locale.) В отличие от описанных выше механизмов, эти модификаторы влияют на операции, помимо сопоставления с образцом регулярных выражений, и поэтому дают более согласованные результаты с другими операторами, включая использование \U, \l, и т.д. в заменах.
Если ни один из вышеперечисленных случаев не применим, для обеспечения обратной совместимости модификатор /d используется по умолчанию. Поскольку это может привести к неожиданным результатам, рекомендуется указать, какой набор правил следует использовать.
Поведение модификатора набора символов до Perl 5.14
До версии 5.14 явных модификаторов не было, но /l подразумевался для регулярных выражений, скомпилированных в рамках use locale, а /d подразумевался в противном случае. Однако, вставка регулярного выражения в другое регулярное выражение игнорирует исходную компиляцию в пользу того, что было активно во время второй компиляции. Было несколько несоответствий (ошибок) с модификатором /d, где правила Юникода использовались неуместно, и наоборот. \p{} не подразумевал правил Юникода, и ни все экземпляры \N{}, до версии 5.12.
Регулярные выражения
Квантификаторы
Квантификаторы используются, когда определенная часть шаблона должна соответствовать определенному количеству (или нескольким количествам) раз. Если квантификатора нет, число совпадений равно ровно одному. Ниже перечислены стандартные квантификаторы:
* Match 0 or more times
+ Match 1 or more times
? Match 1 or 0 times
{n} Match exactly n times
{n,} Match at least n times
{n,m} Match at least n but not more than m times (Если фигурная скобка без экранирования встречается в контексте, отличном от перечисленных выше квантификаторов, где она не является частью последовательности с обратным слешем, например \x{...}, она либо является фатальной синтаксической ошибкой, либо обрабатывается как обычный символ, как правило, с предупреждением об устаревании. Для экранирования её можно предварять обратным слешем ("\{") или заключить в квадратные скобки ("[{]"). Эта модификация позволит в будущем добавлять синтаксические расширения (например, сделать необязательным нижнюю границу квантификатора) и улучшить проверку ошибок квантификаторов).
Квантификатор "*" эквивалентен {0,}, квантификатор "+" эквивалентен {1,}, а квантификатор "?" эквивалентен {0,1}. n и m ограничены неотрицательными целочисленными значениями, меньшими предварительно заданного предела, определенного при построении perl. Обычно это 32766 на наиболее распространённых платформах. Фактический предел можно увидеть в сообщении об ошибке, сгенерированном кодом, подобным этому:
$_ **= $_ , / {$_} / for 2 .. 42; По умолчанию квантифицированный подшаблон «жадный», то есть он соответствует максимально возможному количеству раз (при заданной начальной позиции), при этом позволяя остальной части шаблона соответствовать. Если требуется минимальное количество совпадений, добавьте за квантификатором "?". Обратите внимание, что значения не изменяются, изменяется только «жадность»:
*? Match 0 or more times, not greedily
+? Match 1 or more times, not greedily
?? Match 0 or 1 time, not greedily
{n}? Match exactly n times, not greedily (redundant)
{n,}? Match at least n times, not greedily
{n,m}? Match at least n but not more than m times, not greedily Обычно, когда квантифицированный подшаблон не позволяет остальной части шаблона соответствовать, Perl выполняет обратную подстановку. Однако, это поведение иногда нежелательно. Поэтому Perl предоставляет форму квантификатора «поглощающего».
*+ Match 0 or more times and give nothing back
++ Match 1 or more times and give nothing back
?+ Match 0 or 1 time and give nothing back
{n}+ Match exactly n times and give nothing back (redundant)
{n,}+ Match at least n times and give nothing back
{n,m}+ Match at least n but not more than m times and give nothing back Например,
'aaaa' =~ /a++a/ никогда не будет соответствовать, так как a++ поглотит все "a" в строке и не оставит ничего для оставшейся части шаблона. Эта функция может быть чрезвычайно полезной, чтобы дать Perl подсказки о том, где не следует проводить обратную подстановку. Например, типичная проблема «сопоставить строку в двойных кавычках» может быть наиболее эффективно решена, когда она записана как:
/"(?:[^"\\]++|\\.)*+"/ поскольку нам известно, что если заключительная кавычка не совпадает, обратная подстановка не поможет. См. независимое подвыражение "(?>pattern)" для получения более подробной информации; поглощающие квантификаторы — это просто синтаксический сахар для этого конструктора. Например, вышеприведенный пример также можно записать следующим образом:
/"(?>(?:(?>[^"\\]+)|\\.)*)"/ Обратите внимание, что модификатор «поглощающего» квантификатора не может быть объединён с модификатором «нежадного». Это бессмысленно. Рассмотрим следующую таблицу эквивалентности:
Illegal Legal
------------ ------
X??+ X{0}
X+?+ X{1}
X{min,max}?+ X{min} Последовательности экранирования
Поскольку шаблоны обрабатываются как строки в двойных кавычках, следующее также работает:
\t tab (HT, TAB)
\n newline (LF, NL)
\r return (CR)
\f form feed (FF)
\a alarm (bell) (BEL)
\e escape (think troff) (ESC)
\cK control char (example: VT)
\x{}, \x00 character whose ordinal is the given hexadecimal number
\N{name} named Unicode character or character sequence
\N{U+263D} Unicode character (example: FIRST QUARTER MOON)
\o{}, \000 character whose ordinal is the given octal number
\l lowercase next char (think vi)
\u uppercase next char (think vi)
\L lowercase until \E (think vi)
\U uppercase until \E (think vi)
\Q quote (disable) pattern metacharacters until \E
\E end either case modification or quoted section, think vi Подробности см. в "Quote and Quote-like Operators" в perlop.
Классы символов и другие специальные экранирования
Кроме того, Perl определяет следующие:
Sequence Note Description
[...] [1] Match a character according to the rules of the
bracketed character class defined by the "...".
Example: [a-z] matches "a" or "b" or "c" ... or "z"
[[:...:]] [2] Match a character according to the rules of the POSIX
character class "..." within the outer bracketed
character class. Example: [[:upper:]] matches any
uppercase character.
(?[...]) [8] Extended bracketed character class
\w [3] Match a "word" character (alphanumeric plus "_", plus
other connector punctuation chars plus Unicode
marks)
\W [3] Match a non-"word" character
\s [3] Match a whitespace character
\S [3] Match a non-whitespace character
\d [3] Match a decimal digit character
\D [3] Match a non-digit character
\pP [3] Match P, named property. Use \p{Prop} for longer names
\PP [3] Match non-P
\X [4] Match Unicode "eXtended grapheme cluster"
\1 [5] Backreference to a specific capture group or buffer.
'1' may actually be any positive integer.
\g1 [5] Backreference to a specific or previous group,
\g{-1} [5] The number may be negative indicating a relative
previous group and may optionally be wrapped in
curly brackets for safer parsing.
\g{name} [5] Named backreference
\k<name> [5] Named backreference
\K [6] Keep the stuff left of the \K, don't include it in $&
\N [7] Any character but \n. Not affected by /s modifier
\v [3] Vertical whitespace
\V [3] Not vertical whitespace
\h [3] Horizontal whitespace
\H [3] Not horizontal whitespace
\R [4] Linebreak - [1]
-
См. "Bracketed Character Classes" в perlrecharclass для получения подробной информации.
- [2]
-
См. "POSIX Character Classes" в perlrecharclass для получения подробной информации.
- [3]
-
См. "Unicode Character Properties" в perlunicode для получения подробной информации
- [4]
-
См. "Misc" в perlrebackslash для получения подробной информации.
- [5]
-
См. "Группы захвата" ниже для получения подробной информации.
- [6]
-
См. "Расширенные шаблоны" ниже для получения подробной информации.
- [7]
-
Обратите внимание, что
\Nимеет два значения. В форме\N{NAME}, он соответствует символу или последовательности символов, имя которого NAME; и аналогично, в форме\N{U+hex}, он соответствует символу, чей код Юникода равен hex. В противном случае, он соответствует любому символу, кроме\n. - [8]
-
См. "Extended Bracketed Character Classes" в perlrecharclass для получения подробной информации.
Утверждения
Помимо "^" и "$", Perl определяет следующие утверждения с нулевой шириной:
\b{} Match at Unicode boundary of specified type
\B{} Match where corresponding \b{} doesn't match
\b Match a \w\W or \W\w boundary
\B Match except at a \w\W or \W\w boundary
\A Match only at beginning of string
\Z Match only at end of string, or before newline at the end
\z Match only at end of string
\G Match only at pos() (e.g. at the end-of-match position
of prior m//g) Граница Юникода (\b{}), доступная начиная с версии 5.22, — это место между двумя символами, или перед первым символом в строке, или после последнего символа в строке, где выполняются определенные критерии, определённые Юникодом. См. "\b{}, \b, \B{}, \B" в perlrebackslash для получения подробной информации.
Граница слова (\b) — это место между двумя символами, имеющее \w с одной стороны и \W с другой стороны (в любом порядке), при этом учитываются воображаемые символы в начале и конце строки, как соответствующие \W. (Внутри классов символов \b представляет символ «вставить» вместо границы слова, как и обычно в любой строке в двойных кавычках.) \A и \Z аналогичны "^" и "$", за исключением того, что они не будут соответствовать многократно, когда используется модификатор /m, в то время как "^" и "$" будут соответствовать каждой внутренней границе строки. Для соответствия фактическому концу строки, а не игнорирования необязательной завершающей новой строки, используйте \z.
Утверждение \G можно использовать для цепочки глобальных соответствий (используя m//g), как описано в "Regexp Quote-Like Operators" в perlop. Оно также полезно при написании сканеров типа lex, когда у вас есть несколько шаблонов, которые нужно сопоставить с последовательными подстроками вашей строки; см. предыдущую ссылку. Фактическое место, где \G будет соответствовать, также может быть повлияно с помощью pos() как lvalue: см. "pos" в perlfunc. Обратите внимание, что правило для соответствий нулевой длины (см. "Повторные шаблоны, соответствуют подстроке нулевой длины") несколько изменяется, в том, что содержимое слева от \G не учитывается при определении длины соответствия. Таким образом, следующее не будет соответствовать бесконечно:
my $string = 'ABC';
pos($string) = 1;
while ($string =~ /(.\G)/g) {
print $1;
} Он выведет «А» и затем завершится, так как он рассматривает соответствие как нулевой длины, и поэтому не будет соответствовать в одном и том же месте дважды подряд.
Стоит отметить, что \G при неправильном использовании может привести к бесконечному циклу. Будьте осторожны при использовании шаблонов, содержащих \G в альтернации.
Также обратите внимание, что s/// откажется переписывать часть подстановки, которая уже была заменена; поэтому, например, это остановится после первой итерации, а не перебирая строку в обратном порядке:
$_ = "123456789";
pos = 6;
s/.(?=.\G)/X/g;
print; # prints 1234X6789, not XXXXX6789 Группы захвата
Конструктор группирования ( ... ) создает группы захвата (также называемые буферами захвата). Для ссылки на текущее содержимое группы позже, в том же шаблоне, используйте \g1 (или \g{1} ) для первой, \g2 (или \g{2} ) для второй и так далее. Это называется ссылкой на обратную ссылку. Нет ограничений на количество захваченных подстрок, которые вы можете использовать. Группы нумеруются по левому открывающемуся скобке, являющейся номером 1, и т.д. Если группа не соответствует, связанная обратная ссылка также не соответствует. (Это может произойти, если группа является необязательной или в другом разделе альтернации.) Вы можете опустить "g", и написать "\1", и т.д., но у этой формы есть некоторые проблемы, описанные ниже.
Вы также можете ссылаться на группы захвата относительно, используя отрицательное число, так что \g-1 и \g{-1} оба ссылаются на непосредственно предшествующую группу захвата, а \g-2 и \g{-2} оба ссылаются на группу перед ней. Например:
/
(Y) # group 1
( # group 2
(X) # group 3
\g{-1} # backref to group 3
\g{-3} # backref to group 1
)
/x соответствовало бы тому же, что и /(Y) ( (X) \g3 \g1 )/x. Это позволяет вам вставлять регулярные выражения в более крупные регулярные выражения, не беспокоясь о переиндексации групп захвата.
Можно вообще отказаться от чисел и создать именованные группы захвата. Обозначение — (?<name>...) для объявления и \g{name} для ссылки. (Для совместимости с регулярными выражениями .Net, \g{name} также может быть записано как \k{name}, \k<name> или \k'name'.) name не должно начинаться с цифры и не должно содержать дефисов. Если в одном и том же шаблоне разные группы имеют одинаковое имя, любая ссылка на это имя предполагает самую левую определённую группу. Именованные группы учитываются в абсолютном и относительном нумерации и поэтому могут также ссылаться на эти числа. (Можно делать вещи с именованными группами захвата, которые в противном случае потребовали бы (??{}).)
Содержимое группы захвата динамически ограничено и доступно вне шаблона до конца содержащего блока или до следующего успешного совпадения, в зависимости от того, что произойдёт раньше. (См. "Составные операторы" в perlsyn.) Вы можете ссылаться на них по абсолютному номеру (используя "$1" вместо "\g1", и т.д.); или по имени через хэш %+, используя "$+{name}".
Фигурные скобки обязательны при ссылке на именованные группы захвата, но необязательны для абсолютных или относительных пронумерованных групп. Фигурные скобки безопаснее при создании регулярного выражения путём конкатенации меньших строк. Например, если у вас есть qr/$a$b/, и $a содержат "\g1", и $b содержат "37", вы получите /\g137/, что, вероятно, не то, что вы имели в виду.
Обозначения \g и \k были введены в Perl 5.10.0. До этого не было ни именованных, ни относительных пронумерованных групп захвата. Абсолютные пронумерованные группы ссылались с помощью \1, \2, и т.д., и это обозначение по-прежнему поддерживается (и, вероятно, всегда будет). Но это приводит к некоторым неоднозначностям, если есть более 9 групп захвата, так как \10 может означать либо десятую группу захвата, либо символ, чьей порядковой позицией в восьмеричной системе счисления является 010 (в ASCII это пробел). Perl разрешает эту неоднозначность, интерпретируя \10 как обратную ссылку только в том случае, если до неё открыто не менее 10 левых скобок. Аналогично, \11 является обратной ссылкой только в том случае, если до неё открыто не менее 11 левых скобок. И так далее. \1 и \9 всегда интерпретируются как обратные ссылки. Ниже приведены несколько примеров, которые иллюстрируют эти опасности. Можно избежать неоднозначности, всегда используя \g{} или \g если вы имеете в виду группы захвата; и для восьмеричных констант всегда использовать \o{}, или для \077 и ниже, используя 3 цифры, дополненные ведущими нулями, так как ведущий ноль подразумевает восьмеричную константу.
Обозначение \digit также работает в определенных обстоятельствах за пределами шаблона. Подробности см. в разделе "Предупреждение об использовании \1 вместо $1" ниже.
Примеры:
s/^([^ ]*) *([^ ]*)/$2 $1/; # swap first two words
/(.)\g1/ # find first doubled char
and print "'$1' is the first doubled character\n";
/(?<char>.)\k<char>/ # ... a different way
and print "'$+{char}' is the first doubled character\n";
/(?'char'.)\g1/ # ... mix and match
and print "'$1' is the first doubled character\n";
if (/Time: (..):(..):(..)/) { # parse out values
$hours = $1;
$minutes = $2;
$seconds = $3;
}
/(.)(.)(.)(.)(.)(.)(.)(.)(.)\g10/ # \g10 is a backreference
/(.)(.)(.)(.)(.)(.)(.)(.)(.)\10/ # \10 is octal
/((.)(.)(.)(.)(.)(.)(.)(.)(.))\10/ # \10 is a backreference
/((.)(.)(.)(.)(.)(.)(.)(.)(.))\010/ # \010 is octal
$a = '(.)\1'; # Creates problems when concatenated.
$b = '(.)\g{1}'; # Avoids the problems.
"aa" =~ /${a}/; # True
"aa" =~ /${b}/; # True
"aa0" =~ /${a}0/; # False!
"aa0" =~ /${b}0/; # True
"aa\x08" =~ /${a}0/; # True!
"aa\x08" =~ /${b}0/; # False Несколько специальных переменных также ссылаются на части предыдущего совпадения. $+ возвращает всё, что совпало в последней паре скобок. $& возвращает всю сопоставленную строку. (В какой-то момент $0 тоже, но сейчас он возвращает имя программы.) $` возвращает всё, что идёт перед сопоставленной строкой. $' возвращает всё, что идёт после сопоставленной строки. А $^N содержит то, что было сопоставлено самой последней закрытой группой (подстрокой). $^N может использоваться в расширенных шаблонах (см. ниже), например, для присвоения подстроки переменной.
Эти специальные переменные, как хэш %+ и пронумерованные переменные соответствия ($1, $2, $3, и т.д.) динамически ограничены до конца содержащего блока или до следующего успешного совпадения, в зависимости от того, что произойдёт раньше. (См. "Составные операторы" в perlsyn.)
ПРИМЕЧАНИЕ: Неуспешные совпадения в Perl не сбрасывают переменные совпадения, что облегчает написание кода, который проверяет серию более конкретных случаев и запоминает лучшее совпадение.
ПРЕДУПРЕЖДЕНИЕ: Если ваш код будет выполняться на Perl 5.16 или более ранней версии, имейте в виду, что как только Perl увидит, что вам нужен один из $&, $` или $' где-либо в программе, он должен предоставить их для каждого соответствия шаблону. Это может существенно замедлить вашу программу.
Perl использует тот же механизм для получения $1, $2, и т.д., поэтому вы также платите за каждый шаблон, содержащий скобки захвата. (Чтобы избежать этих затрат при сохранении поведения группирования, используйте расширенное регулярное выражение (?: ... ) вместо этого.) Но если вы никогда не используете $&, $` или $', то шаблоны без скобок захвата не будут подвергаться штрафам. Поэтому избегайте $&, $' и $`, если можете, но если не можете (и некоторые алгоритмы действительно ценят их), как только вы их использовали один раз, используйте их на своё усмотрение, потому что вы уже заплатили за это.
Perl 5.16 ввёл немного более эффективный механизм, который отдельно отмечает, были ли замечены $`, $& и $', и, таким образом, может потребоваться скопировать только часть строки. Perl 5.20 ввёл гораздо более эффективный механизм копирования при записи, который устраняет любые замедления.
В качестве ещё одного обходного решения этой проблемы, Perl 5.10.0 ввёл ${^PREMATCH}, ${^MATCH} и ${^POSTMATCH}, которые эквивалентны $`, $& и $', за исключением того, что они гарантированно определяются только после успешного соответствия, выполненного с модификатором /p (сохранение). Использование этих переменных не влечёт за собой никаких глобальных проблем с производительностью, в отличие от их эквивалентов с знаками препинания, однако в качестве компромисса вы должны сказать Perl, когда хотите их использовать. По состоянию на Perl 5.20, эти три переменные эквивалентны $`, $& и $', и /p игнорируется.
Квотирование метасимволов
В Perl метасимволы, обрамлённые обратным слэшем, — это буквенно-цифровые, такие как \b, \w, \n. В отличие от некоторых других языков регулярных выражений, нет обрамлённых обратным слэшем символов, которые не были бы буквенно-цифровыми. Поэтому всё, что похоже на \\, \(, \), \[, \], \{, или \} всегда интерпретируется как буквальный символ, а не как метасимвол. Раньше это использовалось в распространённом выражении для отключения или цитирования специальных значений метасимволов регулярных выражений в строке, которую вы хотите использовать в качестве шаблона. Просто процитируйте все символы, не являющиеся "словами":
$pattern =~ s/(\W)/\\$1/g; (Если use locale установлено, то это зависит от текущей локали.) Сегодня более распространённым способом является использование функции quotemeta() или метацитируемой последовательности escape \Q для отключения всех специальных значений метасимволов так:
/$unquoted\Q$quoted\E$unquoted/ Будьте осторожны, если вы поместите буквальные обратные слэши (не те, которые находятся внутри интерполированных переменных) между \Q и \E, интерполяция двойного обратного слэша может привести к путанице. Если вам необходимо использовать буквальные обратные слэши внутри \Q...\E, обратитесь к "Подробные сведения о разборе цитируемых конструкций" в perlop.
quotemeta() и \Q подробно описаны в "quotemeta" в perlfunc.
Расширенные шаблоны
Perl также определяет согласованную синтаксическую расширение для функций, отсутствующих в стандартных инструментах, таких как awk и lex. Синтаксис для большинства из них — это пара скобок с вопросительным знаком в качестве первого элемента внутри скобок. Символ после вопросительного знака указывает расширение.
Вопросительный знак был выбран для этого и для конструкции минимального соответствия, потому что 1) вопросительные знаки редки в старых регулярных выражениях и 2) каждый раз, когда вы видите один, вы должны остановиться и «задать вопрос» о том, что происходит. Это психология....
-
(?#text) -
Комментарий. Текст текста игнорируется. Обратите внимание, что Perl закрывает комментарий, как только видит
")", поэтому нет возможности поместить литеральный")"в комментарий. Закрывающей разделитель шаблона необходимо экранировать с помощью обратного слэша, если он встречается в комментарии.См. "/x" для другого способа включения комментариев в шаблонах.
Обратите внимание, что комментарий может находиться практически где угодно, кроме середины последовательности экранирования. Примеры:
qr/foo(?#comment)bar/' # Matches 'foobar' # The pattern below matches 'abcd', 'abccd', or 'abcccd' qr/abc(?#comment between literal and its quantifier){1,3}d/ # The pattern below generates a syntax error, because the '\p' must # be followed immediately by a '{'. qr/\p(?#comment between \p and its property name){Any}/ # The pattern below generates a syntax error, because the initial # '\(' is a literal opening parenthesis, and so there is nothing # for the closing ')' to match qr/\(?#the backslash means this isn't a comment)p{Any}/ # Comments can be used to fold long patterns into multiple lines qr/First part of a long regex(?# )remaining part/ -
(?adlupimnsx-imnsx) -
(?^alupimnsx) -
Ноль или более встроенных модификаторов сопоставления шаблонов, которые должны быть включены (или выключены, если перед ними стоит
"-") для оставшейся части шаблона или оставшейся части группы шаблонов (если таковая имеется).Это особенно полезно для динамически сгенерированных шаблонов, таких как те, которые считываются из файла конфигурации, из аргумента или из таблицы. Рассмотрим случай, когда некоторые шаблоны должны быть регистрозависимыми, а другие — нет: регистронезависимые шаблоны просто должны включать
(?i)в начале шаблона. Например:$pattern = "foobar"; if ( /$pattern/i ) { } # more flexible: $pattern = "(?i)foobar"; if ( /$pattern/ ) { }Эти модификаторы восстанавливаются в конце содержащей группы. Например,
( (?i) blah ) \s+ \g1будет совпадать с
blahв любом регистре, несколькими пробелами и точным (включая регистр!) повторением предыдущего слова, предполагая модификатор/xи отсутствие модификатора/iза пределами этой группы.Эти модификаторы не переносятся в именованные подшаблоны, вызываемые в содержащей группе. Другими словами, шаблон, такой как
((?i)(?&NAME))не изменяет регистрозависимость шаблона NAME.Модификатор переопределяется последующими появлениями этого конструкта в том же объеме, содержащем тот же модификатор, так что
/((?im)foo(?-m)bar)/совпадает со всем содержимым
foobarс учетом регистра, но использует правила/mтолько для частиfoo. Флаг"a"переопределяетaa, а такжеaaпереопределяет"a". То же самое относится к"x"иxx. Следовательно, в/(?-x)foo/xxв обоих
/xи/xxотключаются во время сопоставленияfoo. И в/(?x)foo/x/xно НЕ/xxвключается для сопоставленияfoo. (Можно ошибочно предположить, что поскольку внутренний(?x)уже находится в области видимости/x, результат в конечном итоге будет суммой из них, что даст/xx. Это не так.) Аналогично, выполнение операции, подобной(?xx-x)fooотключает все поведение"x"для сопоставленияfoo, это не то же самое, что вы вычитаете 1"x"из 2, чтобы получить 1"x"оставшимся.Любой из этих модификаторов может быть установлен для глобального применения ко всем регулярным выражениям, скомпилированным в пределах области видимости
use re. См. "'/flags' mode" in re.Начиная с Perl 5.14,
"^"(каретка или знак акцента) непосредственно после"?"— это краткое эквивалентd-imnsx. Флаги (за исключением"d") могут следовать за кареткой, чтобы переопределить ее. Но знак минус не допускается.Обратите внимание, что модификаторы
"a","d","l","p"и"u"являются специальными, поскольку их можно только включить, но не выключить, а модификаторы"a","d","l"и"u"взаимно исключают друг друга: указание одного отменяет другие, и может присутствовать не более одного (или двух"a"). Например,(?-p)будет выдавать предупреждение при компиляции вuse warnings;(?-d:...)и(?dl:...)являются ошибками.Также обратите внимание, что модификатор
"p"является особым, поскольку его присутствие где-либо в шаблоне оказывает глобальное влияние.Отсутствие модификаторов делает это операцией без действия (так зачем вы его указали, если это не сгенерированный код), и начиная с версии 5.30, выдаёт предупреждение по
use re 'strict'. -
(?:pattern) -
(?adluimnsx-imnsx:pattern) -
(?^aluimnsx:pattern) -
Это используется для группировки, а не для захвата; она группирует подвыражения, как
"()", но не создает обратные ссылки, как"()". Поэтому@fields = split(/\b(?:a|b|c)\b/)совпадает с теми же разделителями полей, что и
@fields = split(/\b(a|b|c)\b/)но не выводит сами разделители в качестве дополнительных полей (хотя это поведение "split" в perlfunc, когда его шаблон содержит группы захвата). Также это дешевле, если вам не нужно захватывать символы.
Любые буквы между
"?"и":"действуют как модификаторы флагов, как и в(?adluimnsx-imnsx). Например,/(?s-i:more.*than).*million/iэквивалентно более подробному
/(?:(?s-i)more.*than).*million/iОбратите внимание, что любые конструкции
()внутри этой конструкции по-прежнему будут захватывать, если модификатор/nне активен.Как и в конструкции "(?adlupimnsx-imnsx)",
aaи"a"переопределяют друг друга, так же как иxxи"x". Они не аддитивны. Таким образом, выполнение операции, подобной(?xx-x:foo)отключает все поведение"x"для сопоставленияfoo.Начиная с Perl 5.14,
"^"(каретка или знак акцента) непосредственно после"?"— это краткое эквивалентd-imnsx. Любые положительные флаги (за исключением"d") могут следовать за кареткой, поэтому(?^x:foo)эквивалентно
(?x-imns:foo)Каретка указывает Perl, что эта группа не наследует флаги какого-либо окружающего шаблона, а использует системные значения по умолчанию (
d-imnsx), измененные любыми указанными флагами.Каретка позволяет упростить строковое представление скомпилированных регулярных выражений. Они выглядят так
(?^:pattern)с любыми нестандартными флагами, появляющимися между кареткой и двоеточием. Тест, который анализирует такое строковое представление, таким образом, не должен иметь системные флаги по умолчанию в коде, только каретку. Если в Perl добавлены новые флаги, значение расширения каретки изменится, чтобы включить значения по умолчанию для этих флагов, поэтому тест по-прежнему будет работать без изменений.
Указание отрицательного флага после каретки является ошибкой, так как флаг избыточен.
Мнемоника для
(?^...): Новое начало, поскольку обычное использование каретки — это соответствие в начале. -
(?|pattern) -
Это шаблон «сброса ветви», который обладает особым свойством, что группы захвата нумеруются с той же начальной точки в каждом альтернативном ветвящемся шаблоне. Доступно начиная с perl 5.10.0.
Группы захвата нумеруются слева направо, но внутри этого конструкта нумерация перезапускается для каждой ветви.
Нумерация внутри каждой ветви будет обычной, и любые группы, следующие за этим конструктом, будут пронумерованы так, как если бы этот конструкт содержал только одну ветвь, а именно ту, которая содержит наибольшее количество групп захвата.
Этот конструкт полезен, когда вы хотите захватить одно из нескольких альтернативных соответствий.
Рассмотрим следующий шаблон. Числа под ним показывают, в какой группе будет храниться захваченное содержимое.
# before ---------------branch-reset----------- after / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x # 1 2 2 3 2 3 4Будьте осторожны при использовании шаблона сброса ветви в сочетании с именованными захватами. Именованные захваты реализуются как псевдонимы к пронумерованным группам, содержащим захваты, и это мешает реализации шаблона сброса ветви. Если вы используете именованные захваты в шаблоне сброса ветви, лучше использовать одинаковые имена в том же порядке в каждой из альтернатив:
/(?| (?<a> x ) (?<b> y ) | (?<a> z ) (?<b> w )) /xЕсли этого не сделать, могут возникнуть неожиданности:
"12" =~ /(?| (?<a> \d+ ) | (?<b> \D+))/x; say $+{a}; # Prints '12' say $+{b}; # *Also* prints '12'.Проблема здесь в том, что обе группы с именем
aиbявляются псевдонимами для группы, принадлежащей$1. - Проверочные утверждения Lookaround
-
Утверждения lookaround — это шаблоны нулевой ширины, которые соответствуют определённому шаблону, не включая его в
$&. Положительные утверждения соответствуют, когда их подшаблон соответствует, отрицательные утверждения соответствуют, когда их подшаблон не соответствует. Lookbehind соответствует тексту до текущей позиции совпадения, lookahead соответствует тексту после текущей позиции совпадения.-
(?=pattern) -
(*pla:pattern) -
(*positive_lookahead:pattern) -
Утверждение положительного lookahead нулевой ширины. Например,
/\w+(?=\t)/соответствует слову, за которым следует табуляция, без включения табуляции в$&.Алфавитные формы являются экспериментальными; их использование приводит к предупреждению в категории
experimental::alpha_assertions. -
(?!pattern) -
(*nla:pattern) -
(*negative_lookahead:pattern) -
Утверждение отрицательного lookahead нулевой ширины. Например,
/foo(?!bar)/соответствует любому вхождению "foo", за которым не следует "bar". Однако обратите внимание, что lookahead и lookbehind — это не одно и то же. Вы не можете использовать это для lookbehind.Если вы ищете "bar", за которым не следует "foo",
/(?!foo)bar/не сделает того, что вы хотите. Это потому, что(?!foo)просто говорит, что следующим элементом не может быть "foo" — и это не так, это "bar", поэтому "foobar" будет соответствовать. Используйте lookbehind вместо этого (см. ниже).Алфавитные формы являются экспериментальными; их использование приводит к предупреждению в категории
experimental::alpha_assertions. -
(?<=pattern) -
\K -
(*plb:pattern) -
(*positive_lookbehind:pattern) -
Утверждение положительного lookbehind нулевой ширины. Например,
/(?<=\t)\w+/соответствует слову, которое следует за табуляцией, без включения табуляции в$&.До Perl 5.30 оно работало только для lookbehind фиксированной ширины, но начиная с этой версии оно может обрабатывать переменные длины от 1 до 255 символов как экспериментальную функцию. Эта функция включается автоматически, если вы используете утверждение lookbehind переменной длины, но вызовет предупреждение во время компиляции шаблона, если не отключена, в категории
experimental::vlb. Это предупреждает вас о том, что точное поведение может измениться в случае обратной связи от реального использования в поле; или даже о полном удалении, если обнаруженные проблемы не решаемы практически. Вы можете добиться поведения, близкого к поведению до 5.30, сделав предупреждения в этой категории фатальными.Существует специальная форма этого конструкта, называемая
\K(доступна начиная с Perl 5.10.0), которая заставляет движок регулярных выражений «сохранять» всё, что он сопоставил до\Kи не включать его в$&. Это эффективно обеспечивает lookbehind переменной длины любой длины, не являющейся экспериментальной.И существует техника, которая может использоваться для обработки lookbehind переменной длины в более ранних версиях и длиной более 255 символов. Она описана в http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html.
Обратите внимание, что в
/i, несколько отдельных символов соответствуют двум или трём другим символам. Это делает их переменной длины, а длина 255 относится к максимальному числу символов в совпадении. Например,qr/\N{LATIN SMALL LETTER SHARP S}/iсоответствует последовательности"ss".Ваше утверждение lookbehind может содержать 127 символов Sharp S в
/i, но добавление 128-го сгенерирует ошибку компиляции, так как это может соответствовать 256"s"символам подряд.Использование
\Kвнутри другого утверждения lookaround разрешено, но поведение в настоящее время не определено.По разным причинам
\Kможет быть значительно эффективнее, чем эквивалентный(?<=...)конструкт, и он особенно полезен в ситуациях, когда вы хотите эффективно удалить что-то, следующее за чем-то другим в строке. Напримерs/(foo)bar/$1/g;можно переписать как гораздо более эффективное
s/foo\Kbar//g;Использование модификатора нежадного
"?"может не дать ожидаемых результатов, если он находится внутри группы захвата в конструкте.Алфавитные формы (кроме
\Kявляются экспериментальными; их использование приводит к предупреждению в категорииexperimental::alpha_assertions. -
(?<!pattern) -
(*nlb:pattern) -
(*negative_lookbehind:pattern) -
Утверждение отрицательного lookbehind нулевой ширины. Например,
/(?<!bar)foo/соответствует любому вхождению "foo", за которым не следует "bar".До Perl 5.30 оно работало только для lookbehind фиксированной ширины, но начиная с этой версии оно может обрабатывать переменные длины от 1 до 255 символов как экспериментальную функцию. Эта функция включается автоматически, если вы используете утверждение lookbehind переменной длины, но вызовет предупреждение во время компиляции шаблона, если не отключена, в категории
experimental::vlb.Это предупреждает вас о том, что точное поведение может измениться в случае обратной связи от реального использования в поле; или даже о полном удалении, если обнаруженные проблемы не решаемы практически. Вы можете добиться поведения, близкого к поведению до 5.30, сделав предупреждения в этой категории фатальными.
Существует техника, которая может использоваться для обработки lookbehind переменной длины в более ранних версиях и длиной более 255 символов. Она описана в http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html.
Обратите внимание, что в
/i, несколько отдельных символов соответствуют двум или трём другим символам. Это делает их переменной длины, а длина 255 относится к максимальному числу символов в совпадении. Например,qr/\N{LATIN SMALL LETTER SHARP S}/iсоответствует последовательности"ss".Ваше утверждение lookbehind может содержать 127 символов Sharp S в
/i, но добавление 128-го сгенерирует ошибку компиляции, так как это может соответствовать 256"s"символам подряд.Использование модификатора нежадного
"?"может не дать ожидаемых результатов, если он находится внутри группы захвата в конструкте.Алфавитные формы являются экспериментальными; их использование приводит к предупреждению в категории
experimental::alpha_assertions. -
(?<NAME>pattern) -
(?'NAME'pattern) -
Именованная группа захвата. Абсолютно идентична обычным скобкам захвата
()за исключением того, что к группе можно обратиться по имени в различных конструкциях регулярных выражений (например,\g{NAME}) и получить доступ к ней по имени после успешного совпадения с помощью%+или%-. См. perlvar для получения дополнительной информации о хешах%+и%-.Если несколько разных групп захвата имеют одинаковое имя, то
$+{NAME}будет ссылаться на левую группу, определённую в совпадении.Формы
(?'NAME'pattern)и(?<NAME>pattern)эквивалентны.ПРИМЕЧАНИЕ: Хотя обозначение этого конструкта такое же, как у аналогичной функции в .NET регулярных выражениях, поведение отличается. В Perl группы нумеруются последовательно независимо от того, именованные они или нет. Таким образом, в шаблоне
/(x)(?<foo>y)(z)/$+{foo}будет равно$2, а$3будет содержать 'z' вместо обратного, чего может ожидать хакер регулярных выражений .NET.В настоящее время NAME ограничен только простыми идентификаторами. Другими словами, он должен соответствовать
/^[_A-Za-z][_A-Za-z0-9]*\z/или его расширению Юникода (см. utf8), хотя он не расширяется локалью (см. perllocale).ПРИМЕЧАНИЕ: Для упрощения работы программистов, знакомых с движками регулярных выражений Python или PCRE, вместо
(?<NAME>pattern)можно использовать шаблон(?P<NAME>pattern); однако эта форма не поддерживает использование одинарных кавычек в качестве разделителя для имени. -
\k<NAME> -
\k'NAME' -
Именованная ссылка на обратную ссылку. Похожа на числовые обратные ссылки, за исключением того, что группа обозначается по имени, а не по номеру. Если несколько групп имеют одинаковое имя, то она ссылается на левую группу, определённую в текущем совпадении.
Ошибка ссылаться на имя, не определённое с помощью
(?<NAME>)ранее в шаблоне.Обе формы эквивалентны.
ПРИМЕЧАНИЕ: Для упрощения работы программистов, знакомых с движками регулярных выражений Python или PCRE, вместо
\k<NAME>можно использовать шаблон(?P=NAME). -
(?{ code })
-
-
ПРЕДУПРЕЖДЕНИЕ: Для безопасного использования этой функции необходимо понимать ее ограничения. Выполняемый код со побочными эффектами может вести себя не одинаково в разных версиях, из-за будущих оптимизаций в движке регулярных выражений. Дополнительную информацию см. в разделе "Частота выполнения встроенного кода".
Это утверждение нулевой ширины выполняет любой встроенный код Perl. Оно всегда выполняется успешно, а его возвращаемое значение устанавливается как
$^R.В литеральных шаблонах код парсится одновременно с окружающим кодом. Внутри шаблона управление временно передается обратно парсеру Perl, пока не будет встречена логически соответствующая закрывающая фигурная скобка. Это похоже на то, как обрабатывается выражение индекса массива в литеральной строке, например
"abc$array[ 1 + f('[') + g()]def"В частности, фигурные скобки не обязательно должны быть сбалансированы:
s/abc(?{ f('{'); })/def/Даже в шаблоне, который интерполируется и компилируется во время выполнения, блочные литералы кода будут скомпилированы один раз, во время компиляции Perl; следующее выведет "ABCD":
print "D"; my $qr = qr/(?{ BEGIN { print "A" } })/; my $foo = "foo"; /$foo$qr(?{ BEGIN { print "B" } })/; BEGIN { print "C" }В шаблонах, где текст кода получен из информации времени выполнения, а не присутствует буквально в исходном коде/шаблоне, код компилируется одновременно с компиляцией шаблона, и по соображениям безопасности
use re 'eval'должен быть доступен. Это предотвращает выполнение кодовых фрагментов, предоставленных пользователем в шаблонах.В ситуациях, когда вам нужно включить это с
use re 'eval', вы также должны включить проверку загрязнения. Еще лучше использовать тщательно ограниченное вычисление внутри безопасного отсека. Подробнее об этих механизмах см. perlsec.С точки зрения парсинга, области видимости лексических переменных и замыканий,
/AAA(?{ BBB })CCC/ведет себя примерно как
/AAA/ && do { BBB } && /CCC/Аналогично,
qr/AAA(?{ BBB })CCC/ведет себя примерно как
sub { /AAA/ && do { BBB } && /CCC/ }В частности:
{ my $i = 1; $r = qr/(?{ print $i })/ } my $i = 2; /$r/; # prints "1"Внутри блока
(?{...}),$_относится к строке, по которой выполняется сопоставление регулярного выражения. Вы также можете использоватьpos()для определения текущей позиции сопоставления в этой строке.Блок кода вводит новую область видимости с точки зрения деклараций лексических переменных, но не с точки зрения
localи аналогичных локальных поведений. Таким образом, последующие блоки кода в том же шаблоне по-прежнему будут видеть значения, которые были локализованы в предыдущих блоках. Эти накопленные локализации отменяются либо в конце успешного совпадения, либо если утверждение отменяется (см. "Откат"). Например,$_ = 'a' x 8; m< (?{ $cnt = 0 }) # Initialize $cnt. ( a (?{ local $cnt = $cnt + 1; # Update $cnt, # backtracking-safe. }) )* aaaa (?{ $res = $cnt }) # On success copy to # non-localized location. >x;вначале увеличит
$cntдо 8; затем во время отката его значение будет отменено обратно до 4, что является значением, присвоенным$res. В конце выполнения регулярного выражения$cntбудет отменено обратно к его начальному значению 0.Это утверждение может использоваться в качестве условия в
(?(condition)yes-pattern|no-pattern)выражении switch. Если оно не используется таким образом, результат вычисления code помещается в специальную переменную
$^R. Это происходит немедленно, поэтому$^Rможет использоваться другими(?{ code })утверждениями внутри того же регулярного выражения.Присвоение
$^Rвыше надлежащим образом локализовано, поэтому старое значение$^Rвосстанавливается, если утверждение отменяется; см. "Откат".Обратите внимание, что специальная переменная
$^Nособенно полезна в блоках кода для захвата результатов подстрочных совпадений в переменных без необходимости отслеживания количества вложенных скобок. Например:$_ = "The brown fox jumps over the lazy dog"; /the (\S+)(?{ $color = $^N }) (\S+)(?{ $animal = $^N })/i; print "color = $color, animal = $animal\n"; -
(??{ code }) -
ПРЕДУПРЕЖДЕНИЕ: Для безопасного использования этой функции необходимо понимать ее ограничения. Выполняемый код со побочными эффектами может вести себя не одинаково в разных версиях, из-за будущих оптимизаций в движке регулярных выражений. Дополнительную информацию см. в разделе "Частота выполнения встроенного кода".
Это "отложенное" подвыражение регулярного выражения. Оно ведет себя точно так же, как блок кода
(?{ code })как описано выше, за исключением того, что его возвращаемое значение, вместо присваивания$^R, обрабатывается как шаблон, компилируется, если это строка (или используется как есть, если это объект qr//), затем сопоставляется так, как если бы оно было вставлено вместо этого конструкта.Во время сопоставления этого подшаблона у него есть свой набор захватов, которые действительны во время подсопоставления, но отбрасываются после возвращения управления к основному шаблону. Например, следующее сопоставляется, при этом внутренний шаблон захватывает "B" и сопоставляет "BB", в то время как внешний шаблон захватывает "A";
my $inner = '(.)\1'; "ABBA" =~ /^(.)(??{ $inner })\1/; print $1; # prints "A";Обратите внимание, что это означает, что внутренний шаблон не может ссылаться на группу захвата, определенную снаружи. (Сам блок кода может использовать
$1, и т.д., чтобы ссылаться на группы захвата окружающего шаблона.) Таким образом, хотя('a' x 100)=~/(??{'(.)' x 100})/будет сопоставляться, оно не установит
$1при выходе.Следующий шаблон сопоставляет скобочную группу:
$re = qr{ \( (?: (?> [^()]+ ) # Non-parens without backtracking | (??{ $re }) # Group with matching parens )* \) }x;См. также
(?PARNO)для другого, более эффективного способа выполнения той же задачи.Выполнение отложенного регулярного выражения слишком много раз без потребления любой входной строки также приведет к ошибке. Глубина, на которой это произойдет, скомпилирована в Perl, поэтому ее можно изменить с помощью пользовательской сборки.
-
(?PARNO)(?-PARNO)(?+PARNO)(?R)(?0) -
Рекурсивный подшаблон. Обработайте содержимое заданного буфера захвата в текущем шаблоне как независимый подшаблон и попытайтесь сопоставить его в текущей позиции строки. Информация о состоянии захвата от вызывающей стороны для таких элементов, как обратные ссылки, доступна подшаблону, но буферы захвата, заданные подшаблоном, не видны вызывающей стороне.
Аналогично
(??{ code })за исключением того, что оно не включает выполнение кода или потенциальную компиляцию возвращенной строки шаблона; вместо этого оно обрабатывает часть текущего шаблона, содержащегося внутри указанной группы захвата, как независимый шаблон, который должен совпадать в текущей позиции. Также отличается обработка буферов захвата, в отличие от(??{ code })рекурсивные шаблоны имеют доступ к состоянию соответствия вызывающей стороны, поэтому можно безопасно использовать обратные ссылки.PARNO — это последовательность цифр (не начинающаяся с 0), значение которой отражает номер скобки группы захвата для рекурсии.
(?R)рекурсивно обращается к началу всего шаблона.(?0)— альтернативная синтаксическая конструкция для(?R). Если перед PARNO стоит знак плюс или минус, предполагается, что он относительный, при этом отрицательные числа обозначают предыдущие группы захвата, а положительные — последующие. Таким образом(?-1)относится к наиболее недавно объявленной группе, а(?+1)указывает на следующую группу, подлежащую объявлению. Обратите внимание, что счет для относительной рекурсии отличается от счета для относительных обратных ссылок, поскольку в случае рекурсии не закрытые группы включаются.Следующий шаблон сопоставляет функцию
foo(), которая может содержать сбалансированные скобки в качестве аргумента.$re = qr{ ( # paren group 1 (full function) foo ( # paren group 2 (parens) \( ( # paren group 3 (contents of parens) (?: (?> [^()]+ ) # Non-parens without backtracking | (?2) # Recurse to start of paren group 2 )* ) \) ) ) }x;Если шаблон использовался следующим образом
'foo(bar(baz)+baz(bop))'=~/$re/ and print "\$1 = $1\n", "\$2 = $2\n", "\$3 = $3\n";вывод должен быть следующим:
$1 = foo(bar(baz)+baz(bop)) $2 = (bar(baz)+baz(bop)) $3 = bar(baz)+baz(bop)Если соответствующая группа захвата не определена, это приводит к ошибке. Рекурсия на большую глубину без потребления любой входной строки также приведет к ошибке. Глубина, на которой это произойдет, скомпилирована в Perl, поэтому ее можно изменить с помощью пользовательской сборки.
Следующее демонстрирует, как использование отрицательного индексирования может упростить встраивание рекурсивных шаблонов внутри
qr//конструкта для последующего использования:my $parens = qr/(\((?:[^()]++|(?-1))*+\))/; if (/foo $parens \s+ \+ \s+ bar $parens/x) { # do something here... }Обратите внимание, что этот шаблон ведет себя не так же, как эквивалентный конструкт PCRE или Python той же формы. В Perl вы можете вернуться в рекурсивно обработаную группу, в PCRE и Python рекурсивно обработаная группа обрабатывается как атомарная. Также модификаторы решаются во время компиляции, поэтому конструкции, такие как
(?i:(?1))или(?:(?i)(?1))не влияют на обработку подшаблона. -
(?&NAME) -
Рекурсия к именованному подшаблону. Идентично
(?PARNO)за исключением того, что скобки для рекурсии определяются по имени. Если несколько скобок имеют одинаковое имя, рекурсия происходит к самой левой.Ссылка на имя, которое не объявлено где-либо в шаблоне, является ошибкой.
ПРИМЕЧАНИЕ: Для облегчения работы программистов, знакомых с движками регулярных выражений Python или PCRE, может использоваться шаблон
(?P>NAME)вместо(?&NAME). -
(?(condition)yes-pattern|no-pattern) -
(?(condition)yes-pattern)
-
Условное выражение. Совпадает с yes-pattern, если condition принимает истинное значение, и совпадает с no-pattern в противном случае. Отсутствие шаблона всегда соответствует.
(condition)должно быть одним из:- целое число в скобках
-
(что является допустимым, если соответствующая пара скобок совпала);
- утверждение о просмотре вперёд/назад/оценивание нулевой ширины;
- имя в угловых скобках или одинарных кавычках
-
(что является допустимым, если группа с заданным именем совпала);
-
специальный символ
(R) -
(истинно, когда вычисляется внутри рекурсии или eval). Кроме того,
"R"может быть последован числом, (что будет истинно при вычислении при рекурсии внутри соответствующей группы), или&NAME, в этом случае он будет истинным только при вычислении во время рекурсии в указанной группе.
Вот сводка возможных предикатов:
-
(1)(2)... -
Проверяет, сопоставилась ли пронумерованная группа захвата с чем-либо. Полный синтаксис:
(?(1)then|else) -
(<NAME>)('NAME') -
Проверяет, сопоставилась ли группа с заданным именем с чем-либо. Полный синтаксис:
(?(<name>)then|else) -
(?=...)(?!...)(?<=...)(?<!...) -
Проверяет, соответствует ли шаблон (или не соответствует, для вариантов
"!"). Полный синтаксис:(?(?=lookahead)then|else) -
(?{ CODE }) -
Обрабатывает возвращаемое значение блока кода как условие. Полный синтаксис:
(?(?{ code })then|else) -
(R) -
Проверяет, оценивалось ли выражение внутри рекурсии. Полный синтаксис:
(?(R)then|else) -
(R1)(R2)... -
Проверяет, оценивалось ли выражение во время выполнения непосредственно внутри n-й группы захвата. Эта проверка является регулярным выражением эквивалентом
if ((caller(0))[3] eq 'subname') { ... }Другими словами, она не проверяет весь стек рекурсии.
Полный синтаксис:
(?(R1)then|else) -
(R&NAME) -
Аналогично
(R1), этот предикат проверяет, выполняемся ли мы непосредственно внутри самой левой группы с заданным именем (этот же логический подход используется(?&NAME)для устранения неоднозначностей). Он не проверяет весь стек, а только имя самой внутренней активной рекурсии. Полный синтаксис:(?(R&name)then|else) -
(DEFINE) -
В этом случае yes-шаблон никогда непосредственно не выполняется, и no-шаблон не допускается. Похож по духу на
(?{0}), но более эффективен. Подробнее см. ниже. Полный синтаксис:(?(DEFINE)definitions...)
Например:
m{ ( \( )? [^()]+ (?(1) \) ) }xсоответствует куску, не содержащему скобок, возможно, включенному в сами скобки.
Особой формой является предикат
(DEFINE), который никогда не выполняет свой yes-шаблон непосредственно и не допускает no-шаблона. Это позволяет определять подшаблоны, которые будут выполняться только механизмом рекурсии. Таким образом, вы можете определить набор правил регулярных выражений, которые могут быть объединены в любой выбранный вами шаблон.Рекомендуется размещать блок DEFINE в конце шаблона и называть все подшаблоны, определенные внутри него.
Также следует отметить, что шаблоны, определенные таким образом, вероятно, не будут такими эффективными, так как оптимизатор не очень умён в их обработке.
Пример использования:
/(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT)) (?(DEFINE) (?<NAME_PAT>....) (?<ADDRESS_PAT>....) )/xОбратите внимание, что группы захвата, сопоставленные внутри рекурсии, недоступны после возвращения из рекурсии, поэтому необходим дополнительный уровень групп захвата. Таким образом,
$+{NAME_PAT}не будет определен, хотя$+{NAME}будет.Наконец, помните, что подшаблоны, созданные внутри блока DEFINE, учитываются в абсолютном и относительном количестве захватов, поэтому это:
my @captures = "a" =~ /(.) # First capture (?(DEFINE) (?<EXAMPLE> 1 ) # Second capture )/x; say scalar @captures;Выведет 2, а не 1. Это особенно важно, если вы планируете компилировать определения с оператором
qr//и в дальнейшем интерполировать их в другой шаблон. -
(?>pattern) -
(*atomic:pattern) -
«Независимое» подвыражение, которое соответствует подстроке, которую шаблон pattern сопоставил бы, если бы был закреплён в данном положении, и которое соответствует только этой подстроке. Этот конструкт полезен для оптимизации того, что в противном случае было бы «вечными» соответствиями, потому что он не выполняет обратную подстановку (см. "Обратная подстановка"). Он также может быть полезен в тех местах, где желательна семантика «захват всего, что возможно, и ничего не возвращать».
Например:
^(?>a*)abникогда не будет соответствовать, так как(?>a*)(закреплённый в начале строки, как указано выше) будет соответствовать всем символам"a"в начале строки, оставляя никаких"a"дляabсопоставления. В противоположность этому,a*abбудет соответствовать тому же, что иa+b, так как сопоставление подгруппыa*зависит от следующей группыab(см. "Обратная подстановка"). В частности,a*внутриa*abбудет соответствовать меньшему количеству символов, чем автономныйa*, так как это заставляет соответствовать хвосту.(?>pattern)не отключает обратную подстановку полностью после того, как она совпала. Всё ещё возможно выполнять обратную подстановку за пределами конструкции, но не внутрь неё. Так что((?>a*)|(?>b*))arвсё ещё будет сопоставлять "bar".Эффект, похожий на
(?>pattern)может быть достигнут, написав(?=(pattern))\g{-1}. Это соответствует той же подстроке, что и автономныйa+, а последующий\g{-1}съедает сопоставленную строку; таким образом, он превращает утверждение нулевой длины в аналог(?>...). (Различие между этими двумя конструкциями заключается в том, что вторая использует группу захвата, тем самым сдвигая порядковые номера обратных ссылок в остальной части регулярного выражения.)Рассмотрите этот шаблон:
m{ \( ( [^()]+ # x+ | \( [^()]* \) )+ \) }xЭто будет эффективно соответствовать непустой группе с соответствием скобок на две глубины или меньше. Однако, если такой группы нет, он будет работать практически вечно на длинной строке. Это происходит потому, что существует так много способов разбить длинную строку на несколько подстрок. Именно это делает
(.+)+, а(.+)+подобно подшаблону указанного шаблона. Подумайте, как шаблон выше определяет отсутствие соответствия на((()aaaaaaaaaaaaaaaaaaза несколько секунд, но каждый дополнительный символ удваивает это время. Эта экспоненциальная производительность заставит ваше приложение зависнуть. Однако, небольшое изменение в этом шаблонеm{ \( ( (?> [^()]+ ) # change x+ above to (?> x+ ) | \( [^()]* \) )+ \) }xкоторый использует
(?>...)соответствует точно тому, что делает предыдущий (проверьте это самостоятельно, это будет продуктивной работой), но заканчивается в четыре раза быстрее при использовании на аналогичной строке с 1000000"a". Однако имейте в виду, что при применении этой конструкции к квантификатору в настоящее время отображается сообщение об ошибке под прагмойuse warningsили переключателем -w, сообщая, что"matches null string many times in regex".Для простых групп, таких как шаблон
(?> [^()]+ ), аналогичный эффект можно достичь с помощью отрицательного прогнозирующего поиска, как в[^()]+ (?! [^()] ). Это было всего в 4 раза медленнее на строке с 1000000"a".Семантика «захват всего, что возможно, и ничего не возвращать» желательна во многих ситуациях, когда на первый взгляд простое
()*кажется правильным решением. Предположим, мы анализируем текст, где комментарии ограничены"#", за которым следует некоторые необязательные (горизонтальные) пробелы. Вопреки внешнему виду,#[ \t]*не является правильным подвыражением для сопоставления разделителя комментария, потому что он может «отказаться» от некоторых пробелов, если остальную часть шаблона можно сделать так, чтобы он соответствовал таким способом. Правильным ответом является одно из этих выражений:(?>#[ \t]*) #[ \t]*(?![ \t])Например, чтобы захватить непустые комментарии в
$1, необходимо использовать одно из этих выражений:/ (?> \# [ \t]* ) ( .+ ) /x; / \# [ \t]* ( [^ \t] .* ) /x;Какой из них вы выберете, зависит от того, какое из этих выражений лучше отражает вышеуказанное описание комментариев.
В некоторых литературе эта конструкция называется «атомным сопоставлением» или «положительным сопоставлением».
Позитивные квантификаторы эквивалентны размещению элемента, к которому они применяются, внутри одной из этих конструкций. Следующие эквивалентности применяются:
Quantifier Form Bracketing Form --------------- --------------- PAT*+ (?>PAT*) PAT++ (?>PAT+) PAT?+ (?>PAT?) PAT{min,max}+ (?>PAT{min,max})Вложенные
(?>...)конструкции не являются бесполезными операциями, даже если на первый взгляд они могут показаться таковыми. Это происходит потому, что вложенные(?>...)могут ограничивать внутреннюю обратную подстановку, которая в противном случае могла бы произойти. Например,"abc" =~ /(?>a[bc]*c)/соответствует, но
"abc" =~ /(?>a(?>[bc]*)c)/не соответствует.
Альфа-форма (
(*atomic:...)) находится на стадии эксперимента; использование её приводит к предупреждению в категорииexperimental::alpha_assertions. -
(?[ ]) -
См. "Расширенные символьные классы в скобках" в perlrecharclass.
Обратите внимание, что эта функция на данный момент экспериментальная; её использование приводит к предупреждению в категории
experimental::regex_sets.
Обратная подстановка
ПРИМЕЧАНИЕ: Этот раздел представляет абстрактное приближение поведения регулярных выражений. Для более строгого (и сложного) представления правил, участвующих в выборе соответствия среди возможных альтернатив, см. "Объединение частей RE".
Основной особенностью сопоставления регулярных выражений является понятие обратной подстановки, которое в настоящее время используется (при необходимости) всеми квантификаторами регулярных не-положительных выражений, а именно "*", *?, "+", +?, {n,m}, и {n,m}?. Обратная подстановка часто оптимизируется внутри, но общий принцип, изложенный здесь, действителен.
Для того, чтобы регулярное выражение соответствовало, все регулярное выражение должно соответствовать, а не только часть его. Таким образом, если начало шаблона, содержащего квантификатор, преуспевает таким образом, что последующие части шаблона терпят неудачу, движок сопоставления возвращается назад и пересчитывает начальную часть – вот почему это называется обратной подстановкой.
Вот пример обратной подстановки: Предположим, вы хотите найти слово, следующее за "foo" в строке "Food is on the foo table.":
$_ = "Food is on the foo table.";
if ( /\b(foo)\s+(\w+)/i ) {
print "$2 follows $1.\n";
} Когда выполняется сопоставление, первая часть регулярного выражения (\b(foo)) находит возможную совпадающую подстроку в самом начале строки и загружает $1 значением "Foo". Однако, как только механизм сопоставления видит, что после "Foo", которое было сохранено в $1, нет пробела, он понимает свою ошибку и начинает снова с символа, следующего за местом предполагаемого совпадения. На этот раз он продвигается до следующего вхождения "foo". Регулярное выражение в полном объеме совпадает на этот раз, и вы получаете ожидаемый результат "table follows foo".
Иногда минимальное сопоставление может сильно помочь. Представьте, что вам нужно сопоставить всё между "foo" и "bar". Изначально вы пишете что-то вроде этого:
$_ = "The food is under the bar in the barn.";
if ( /foo(.*)bar/ ) {
print "got <$1>\n";
} Что, возможно, неожиданно даёт:
got <d is under the bar in the > Это потому, что .* было жадным, поэтому вы получаете всё между первым "foo" и последним "bar". Здесь эффективнее использовать минимальное сопоставление, чтобы убедиться, что вы получаете текст между "foo" и первым последующим "bar".
if ( /foo(.*?)bar/ ) { print "got <$1>\n" }
got <d is under the > Вот ещё один пример. Предположим, вы хотите сопоставить число в конце строки и также сохранить предшествующую часть совпадения. Поэтому вы пишете так:
$_ = "I have 2 numbers: 53147";
if ( /(.*)(\d*)/ ) { # Wrong!
print "Beginning is <$1>, number is <$2>.\n";
} Это вообще не сработает, потому что .* было жадным и поглотило всю строку. Поскольку \d* может сопоставляться с пустой строкой, полное регулярное выражение успешно совпало.
Beginning is <I have 2 numbers: 53147>, number is <>. Вот несколько вариантов, большинство из которых не работают:
$_ = "I have 2 numbers: 53147";
@pats = qw{
(.*)(\d*)
(.*)(\d+)
(.*?)(\d*)
(.*?)(\d+)
(.*)(\d+)$
(.*?)(\d+)$
(.*)\b(\d+)$
(.*\D)(\d+)$
};
for $pat (@pats) {
printf "%-12s ", $pat;
if ( /$pat/ ) {
print "<$1> <$2>\n";
} else {
print "FAIL\n";
}
} Это выведет:
(.*)(\d*) <I have 2 numbers: 53147> <>
(.*)(\d+) <I have 2 numbers: 5314> <7>
(.*?)(\d*) <> <>
(.*?)(\d+) <I have > <2>
(.*)(\d+)$ <I have 2 numbers: 5314> <7>
(.*?)(\d+)$ <I have 2 numbers: > <53147>
(.*)\b(\d+)$ <I have 2 numbers: > <53147>
(.*\D)(\d+)$ <I have 2 numbers: > <53147> Как видите, это может быть немного сложно. Важно понимать, что регулярное выражение — это всего лишь набор утверждений, которые дают определение успешного сопоставления. Может быть 0, 1 или несколько способов, которыми определение может совпасть со строкой. И если существует несколько способов, которыми это может совпасть, вам нужно понять обратную подстановку, чтобы знать, какой вариант успеха вы получите.
При использовании утверждений и отрицаний с опережающим и отстающим взглядом всё это может стать ещё сложнее. Представьте, что вы хотите найти последовательность нецифр, за которой не следует "123". Вы можете попробовать написать это как
$_ = "ABC123";
if ( /^\D*(?!123)/ ) { # Wrong!
print "Yup, no 123 in $_\n";
} Но это не будет соответствовать; по крайней мере, не так, как вы надеетесь. Оно утверждает, что в строке нет "123". Вот более чёткое представление о том, почему этот шаблон соответствует, вопреки распространённому мнению:
$x = 'ABC123';
$y = 'ABC445';
print "1: got $1\n" if $x =~ /^(ABC)(?!123)/;
print "2: got $1\n" if $y =~ /^(ABC)(?!123)/;
print "3: got $1\n" if $x =~ /^(\D*)(?!123)/;
print "4: got $1\n" if $y =~ /^(\D*)(?!123)/; Это выводит
2: got ABC
3: got AB
4: got ABC Вы могли ожидать, что тест 3 не пройдёт, так как он, кажется, является более универсальной версией теста 1. Важное различие между ними заключается в том, что тест 3 содержит квантификатор (\D*) и, следовательно, может использовать обратную подстановку, тогда как тест 1 не будет. Что происходит, так это то, что вы спросили: "Верно ли, что в начале $x, после 0 или более нецифр, есть что-то, что не является "123"? Если совпадение шаблона разрешило \D* расшириться до "ABC", это привело бы к неудаче всего шаблона.
Двигатель поиска первоначально сопоставит \D* со строкой "ABC". Затем он попытается сопоставить (?!123) со строкой "123", что не получится. Но поскольку в регулярном выражении используется квантификатор (\D*), движок поиска может выполнить обратную подстановку и повторно попробовать сопоставление, надеясь на совпадение всего регулярного выражения.
Шаблон действительно, действительно хочет преуспеть, поэтому он использует стандартный подход — отступление и повторная попытка — и позволяет \D* расшириться до просто "AB" в этот раз. Теперь действительно есть что-то, что следует за "AB", что не является "123". Это "C123", что достаточно.
Мы можем справиться с этим, используя утверждение и отрицание. Мы скажем, что первая часть в $1 должна быть последовать как цифрой, так и чем-то, что не является "123". Помните, что выражения с опережающим и отстающим взглядом — нулевой длины; они только проверяют, но не потребляют никакой части строки в своем сопоставлении. Таким образом, переписывание таким образом даёт то, что вы ожидали; то есть, случай 5 не пройдёт, но случай 6 пройдёт:
print "5: got $1\n" if $x =~ /^(\D*)(?=\d)(?!123)/;
print "6: got $1\n" if $y =~ /^(\D*)(?=\d)(?!123)/;
6: got ABC Другими словами, два утверждения нулевой ширины рядом работают так, как будто они объединены логическим И, как вы бы использовали любые встроенные утверждения: /^$/ совпадает только тогда, когда вы находитесь в начале строки и в конце строки одновременно. Более глубокая истина заключается в том, что смежное расположение в регулярных выражениях всегда означает И, за исключением случаев, когда вы явно пишете ИЛИ, используя вертикальную черту. /ab/ означает сопоставить "a" И (затем) сопоставить "b", хотя попытки сопоставления выполняются в разных позициях, потому что "a" не утверждение нулевой ширины, а утверждение единичной ширины.
ПРЕДУПРЕЖДЕНИЕ: Определённые сложные регулярные выражения могут занимать экспоненциальное время для решения из-за огромного числа возможных способов, которыми они могут использовать обратную подстановку для поиска совпадения. Например, без внутренних оптимизаций, выполняемых двигателем регулярных выражений, это займёт болезненно долгое время:
'aaaaaaaaaaaa' =~ /((a{0,5}){0,5})*[c]/ И если бы вы использовали "*" внутри групп вместо ограничения их 0–5 совпадениями, тогда это заняло бы вечность — или пока не закончился бы стек.
Более того, эти внутренние оптимизации не всегда применимы. Например, если вы поставили {0,5} вместо "*" на внешней группе, ни одна текущая оптимизация не применима, и сопоставление занимает много времени.
Мощным инструментом для оптимизации таких монстров является то, что известно как "независимая группа", которая не выполняет обратную подстановку (см. "(?>pattern)"). Обратите также внимание, что утверждения опережающего/отстающего взгляда нулевой длины не будут обращаться к результату для обеспечения совпадения с хвостом, так как они находятся в "логическом" контексте: рассматривается только вопрос о том, совпадают ли они или нет. Пример, где побочные эффекты опережающего взгляда могли повлиять на последующее совпадение, см. "(?>pattern)".
Скриптовые блоки
Скриптовый блок — это, по сути, последовательность символов, все из одного Unicode-скрипта (см. "Скрипты" в perlunicode), например, латинский или греческий. В большинстве мест одно слово никогда не будет написано на нескольких скриптах, если это не атака подмены. Известный пример:
paypal.com Эти буквы могут быть все латинскими (как в примере выше), или все кириллическими (кроме точки), или смешанными из этих двух. В случае интернет-адреса .com будет на латинице, а любые кириллические символы сделают это смешанным, а не блоком скрипта. Кто-то, нажав на такую ссылку, не попадет на настоящий веб-сайт PayPal, но злоумышленник создаст подделку, чтобы попытаться собрать конфиденциальную информацию.
Начиная с Perl 5.28, стало легко обнаруживать строки, которые не являются скриптовыми блоками. Просто заключите почти любой шаблон, например, один из этих:
(*script_run:pattern)
(*sr:pattern) После успешного сопоставления шаблоном pattern он подвергается дополнительному условию, что каждый символ в нём должен принадлежать одному и тому же скрипту (см. исключения ниже). Если это не так, происходит обратная подстановка, пока не будет найдено что-то, что принадлежит одному и тому же скрипту, или пока все возможности не будут исчерпаны. Это может вызвать много обратной подстановки, но, как правило, это произойдёт только при вредоносном вводе, хотя замедление может вызвать атаку типа отказ в обслуживании. Если ваши потребности позволяют, лучше сделать шаблон атомарным, чтобы уменьшить количество обратной подстановки. Это так похоже на то, что вы хотите, что вместо этого:
(*script_run:(?>pattern)) вы можете написать либо это:
(*atomic_script_run:pattern)
(*asr:pattern) (См. "(?>pattern)".)
В Тайване, Японии и Корее часто встречается текст со смешением символов из их собственных скриптов и базового китайского. Perl следует стандарту Unicode UTS 39 (http://unicode.org/reports/tr39/) по механизмам безопасности Unicode, позволяя такие смешения. Например, японские скрипты катакана и хирагана часто смешиваются на практике вместе с некоторыми китайскими символами и поэтому рассматриваются как единый скриптовый блок в Perl.
Правила сопоставления десятичных цифр несколько жёстче. Многие скрипты имеют свои собственные наборы цифр, эквивалентные западным 0 через 9. У некоторых, например, у арабских, их несколько. Чтобы строка считалась скриптовым блоком, все цифры в ней должны быть из одного набора из десяти, как определено первой встретившейся цифрой. Например,
qr/(*script_run: \d+ \b )/x гарантирует, что все сопоставленные цифры будут из одного набора из десяти. Вы не получите подобную цифру из другого скрипта, которая будет иметь другое значение, чем кажется.
В Unicode есть три псевдо-скрипта, которые обрабатываются специально.
"Неизвестно" применяется к кодовым точкам, значение которых ещё не определено. В настоящее время Perl будет сопоставлять как скриптовый блок любую строку из одного символа, состоящую из одной из этих кодовых точек. Но любая строка длиной более одного кодового знака, содержащая одну из этих кодовых точек, не будет считаться скриптовым блоком.
"Наследуемый" применяется к символам, которые изменяют другой символ, например, ударение. Они считаются принадлежащими скрипту основного символа и поэтому никогда не приводят к тому, что скриптовый блок не соответствует.
Другой — "Общий". Он состоит в основном из знаков препинания, эмодзи и символов, используемых в математике и музыке, ASCII-цифр 0 через 9, и полных форм этих цифр. Эти символы могут встречаться в тексте, смешанные в разных скриптах мира. Они также не приводят к тому, что скриптовый блок не соответствует. Но, как и в других скриптах, все цифры в блоке должны принадлежать одному и тому же набору из десяти.
Этот конструктор не захватывающий. Вы можете добавить круглые скобки к pattern для захвата, если нужно. Вам придётся это сделать, если вы планируете использовать "(*ACCEPT) (*ACCEPT:arg)" и не хотите, чтобы проверка скриптового блока её обошла.
Эта функция является экспериментальной, и точный синтаксис и детали работы могут быть изменены; использование её даёт предупреждение в категории experimental::script_run.
Свойство Script_Extensions, как модифицировано в UTS 39 (http://unicode.org/reports/tr39/), используется в качестве основы для этой функции.
Подводя итог,
-
Все последовательности длиной 0 или 1 являются скриптовыми блоками.
-
Более длинная последовательность является скриптовым блоком, если и только если выполняются все следующие условия:
-
Ни одна кодовая точка в последовательности не имеет свойства
Script_ExtensionUnknown.В настоящее время это означает, что все кодовые точки в последовательности были назначены Unicode как символы, которые не являются кодовыми точками частного использования или суррогатными.
-
Все символы в последовательности принадлежат скрипту Общий и/или Наследуемый и/или одному другому скрипту.
Скрипт символа определяется свойством
Script_Extensions, как модифицировано UTS 39 (http://unicode.org/reports/tr39/), как описано выше. -
Все десятичные цифры в последовательности принадлежат одному блоку из десяти последовательных цифр.
-
Специальные глаголы управления обратной трассировкой
Эти специальные шаблоны обычно имеют вид (*VERB:arg). Если не указано иное, аргумент arg является необязательным; в некоторых случаях он является обязательным.
Любой шаблон, содержащий специальный глагол обратной трассировки, допускающий аргумент, обладает особым поведением: при выполнении он устанавливает переменные текущего пакета $REGERROR и $REGMARK. При этом применяются следующие правила:
При неудаче переменная $REGERROR будет установлена в значение arg глагола-шаблона, если глагол был вовлечён в неудачу соответствия. Если часть arg шаблона опущена, то $REGERROR будет установлена в имя последнего шаблона (*MARK:NAME), выполненного, или в TRUE, если такого не было. Кроме того, переменная $REGMARK будет установлена в FALSE.
При успешном соответствии переменная $REGERROR будет установлена в FALSE, а переменная $REGMARK — в имя последнего шаблона (*MARK:NAME), выполненного. Подробнее см. объяснение глагола (*MARK:NAME) ниже.
ПРИМЕЧАНИЕ: $REGERROR и $REGMARK не являются магическими переменными, такими как $1 и большинство других переменных, связанных с регулярными выражениями. Они не являются локальными для области видимости, а также не являются только для чтения, а вместо этого являются переменными пакета, похожими на $AUTOLOAD. Они устанавливаются в пакете, содержащем код, выполнивший регулярное выражение (а не тот, который его скомпилировал, если они отличаются). При необходимости вы можете использовать local для локализации изменений этих переменных в определенной области видимости перед выполнением регулярного выражения.
Если шаблон не содержит специальный глагол обратной трассировки, допускающий аргумент, то $REGERROR и $REGMARK не затрагиваются вообще.
- Глаголы
-
-
(*PRUNE)(*PRUNE:NAME) -
Этот шаблон нулевой ширины обрезает дерево обратной трассировки в текущей точке при возврате назад при неудаче. Рассмотрим шаблон
/A (*PRUNE) B/, где A и B — сложные шаблоны. До тех пор, пока не будет достигнут глагол(*PRUNE), A может возвращаться назад по мере необходимости для соответствия. После его достижения соответствие продолжается в B, которое также может возвращаться назад по мере необходимости; однако, если B не соответствует, то дальнейшего возврата назад не произойдёт, и шаблон полностью провалится в текущей исходной позиции.Следующий пример подсчитывает все возможные совпадающие строки в шаблоне (без фактического совпадения с ними).
'aaab' =~ /a+b?(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";что даёт:
aaab aaa aa a aab aa a ab a Count=9Если мы добавим глагол
(*PRUNE)перед подсчётом, как в следующем примере'aaab' =~ /a+b?(*PRUNE)(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";мы предотвратим возврат назад и найдём количество наибольшей совпадающей строки в каждой точке начала совпадения следующим образом:
aaab aab ab Count=3В шаблоне может использоваться любое количество утверждений
(*PRUNE).См. также
"(?>pattern)"и позиционные квантификаторы для других способов управления обратной трассировкой. В некоторых случаях использование(*PRUNE)может быть заменено на(?>pattern)без функциональных различий; однако,(*PRUNE)может использоваться для обработки случаев, которые не могут быть выражены с помощью одного(?>pattern). -
(*SKIP)(*SKIP:NAME) -
Этот шаблон нулевой ширины похож на
(*PRUNE), за исключением того, что при неудаче он также указывает, что любая текст, соответствующий шаблону(*SKIP)вплоть до его выполнения, не может быть частью любого соответствия данного шаблона. Это фактически означает, что движок регулярных выражений «пропускает» вперёд до этой позиции при неудаче и пытается снова сопоставить (предполагая, что есть достаточно места для сопоставления).Имя шаблона
(*SKIP:NAME)имеет особое значение. Если был встречен(*MARK:NAME), то используется именно эта позиция как «точка пропуска». Если такой(*MARK)не встречался, то оператор(*SKIP)не имеет эффекта. При использовании без имени «точка пропуска» находится в том месте, где была точка совпадения при выполнении шаблона(*SKIP).Сравните следующее с примерами в
(*PRUNE); обратите внимание, что строка вдвое длиннее:'aaabaaab' =~ /a+b?(*SKIP)(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";выводит
aaab aaab Count=2После того, как 'aaab' в начале строки сопоставится и будет выполнен
(*SKIP), следующей начальной точкой будет та, где был курсор при выполнении(*SKIP). -
(*MARK:NAME)(*:NAME) -
Этот шаблон нулевой ширины может использоваться для маркировки точки, достигнутой в строке, когда определённая часть шаблона успешно сопоставлена. Эту метку можно назвать. Позже шаблон
(*SKIP)пропустит вперёд до этой точки, если при неудаче произойдёт возврат назад. Разрешено любое количество шаблонов(*MARK), и часть NAME может быть дублирована.В дополнение к взаимодействию с шаблоном
(*SKIP),(*MARK:NAME)может быть использован для «меток» ветви шаблона, так что после соответствия программа может определить, какие ветви шаблона участвовали в соответствиях.При успешном соответствии переменная
$REGMARKбудет установлена в имя последнего выполненного шаблона(*MARK:NAME), который был задействован в соответствии.Это может быть использовано для определения ветви шаблона, которая соответствовала, без использования отдельной группы захвата для каждой ветви, что, в свою очередь, может привести к улучшению производительности, так как Perl не может оптимизировать
/(?:(x)|(y)|(z))/так эффективно, как что-то вроде/(?:x(*MARK:x)|y(*MARK:y)|z(*MARK:z))/.Когда соответствие завершилось неудачей, и если другой глагол не участвовал в неудаче сопоставления и не предоставил своё имя для использования, то переменная
$REGERRORбудет установлена в имя последнего выполненного шаблона(*MARK:NAME).См. "(*SKIP)" для получения дополнительной информации.
В качестве сокращения
(*MARK:NAME)может быть записано(*:NAME). -
(*THEN)(*THEN:NAME) -
Это аналогично оператору «вырезать группу»
::из Perl 6. Как и(*PRUNE), этот глагол всегда соответствует, а при возврате назад при неудаче заставляет движок регулярных выражений попробовать следующую альтернативу во внутренней вложенной группе (запрещающей или иной), имеющей альтернативы. Две ветви(?(condition)yes-pattern|no-pattern)не считаются альтернативой с точки зрения(*THEN).Его название происходит из наблюдения, что этот оператор в сочетании с оператором чередования (
"|") может быть использован для создания по сути блока if/then/else на основе шаблонов:( COND (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ )Обратите внимание, что если этот оператор используется, но не внутри альтернативы, то он действует точно как оператор
(*PRUNE)./ A (*PRUNE) B /равно
/ A (*THEN) B /но
/ ( A (*THEN) B | C ) /не равно
/ ( A (*PRUNE) B | C ) /поскольку после соответствия A, но неудачи на B, глагол
(*THEN)вернётся назад и попробует C; но глагол(*PRUNE)просто провалится. -
(*COMMIT)(*COMMIT:arg) -
Это Perl 6 «шаблон подтверждения»
<commit>или:::. Это шаблон нулевой ширины, аналогичный(*SKIP), за исключением того, что при возврате назад при неудаче он заставляет соответствие полностью провалиться. Больше попыток найти корректное соответствие путём продвижения указателя начала не будет. Например,'aaabaaab' =~ /a+b?(*COMMIT)(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";выводит
aaab Count=1Другими словами, как только будет достигнут
(*COMMIT), и если шаблон не соответствует, то движок регулярных выражений не будет пытаться выполнить дальнейшее соответствие в остальной части строки. -
(*FAIL)(*F)(*FAIL:arg) -
Этот шаблон ничего не сопоставляет и всегда проваливается. Он может быть использован для принудительного возврата назад. Он эквивалентен
(?!), но легче читается. Фактически,(?!)оптимизируется во внутренний(*FAIL). Вы можете указать аргумент, так что если соответствие завершится неудачей из-за этой директивыFAIL, аргумент можно получить из$REGERROR.Вероятно, он полезен только в сочетании с
(?{})или(??{}). -
(*ACCEPT)(*ACCEPT:arg) -
Этот шаблон ничего не сопоставляет и вызывает завершение успешного соответствия в точке, в которой был встречен шаблон
(*ACCEPT), независимо от того, есть ли ещё что-то для сопоставления в строке. При вложении в шаблон, например, рекурсии, или в подшаблоне, динамически сгенерированном через(??{}), завершается только внутренний шаблон.Если
(*ACCEPT)находится внутри групп захвата, то группы отмечаются как завершенные в точке, в которой был встречен(*ACCEPT). Например:'AB' =~ /(A (A|B(*ACCEPT)|C) D)(E)/x;будет соответствовать, и
$1будетAB, а$2будет"B",$3не будет установлена. Если в внутренних скобках была согласована другая ветвь, например, в строке 'ACDE', то"D"и"E"также должны были совпадать.Вы можете предоставить аргумент, который будет доступен в переменной
$REGMARKпосле завершения соответствия.
-
Предупреждение об использовании \1 вместо $1
Некоторые люди привыкли писать:
$pattern =~ s/(\W)/\\\1/g; Это сохраняется (для \1 до \9) для правой части подстановки, чтобы не шокировать фанатов sed, но это плохая привычка. Всё потому, что в PerlThink правая часть s/// — это строка с двойными кавычками. \1 в обычной строке с двойными кавычками означает управляющий символ A. Обычное значение \1 в Unix подстроено для s///. Однако, если вы приобретёте эту привычку, у вас возникнут проблемы, если вы добавите модификатор /e.
s/(\d+)/ \1 + 1 /eg; # causes warning under -w Или если вы попытаетесь сделать
s/(\d+)/\1000/; Вы не можете разобрать это, сказав \{1}000, в то время как вы можете это исправить с помощью ${1}000. Операция интерполяции не следует путать с операцией сопоставления обратной ссылки. Несомненно, они означают две разные вещи в левой части s///.
Повторяющиеся шаблоны, сопоставляющие подстроку нулевой длины
ПРЕДУПРЕЖДЕНИЕ: Следующий материал (и проза) сложные. Этот раздел нуждается в переработке.
Регулярные выражения предоставляют лаконичный и мощный язык программирования. Как и большинство других мощных инструментов, мощь сочетается со способностью нанести ущерб.
Распространенным злоупотреблением этой мощью является создание бесконечных циклов с помощью регулярных выражений, например, с таким безобидным выражением:
'foo' =~ m{ ( o? )* }x; Выражение o? соответствует началу строки "foo", и поскольку позиция в строке не меняется при совпадении, o? будет соответствовать снова и снова из-за квантификатора "*". Другой распространенный способ создания подобного цикла — использование модификатора циклического повторения /g:
@matches = ( 'foo' =~ m{ o? }xg ); или
print "match: <$&>\n" while 'foo' =~ m{ o? }xg; или цикл, подразумеваемый split().
Однако, многолетний опыт показал, что многие задачи программирования могут быть значительно упрощены с помощью повторяющихся подвыражений, которые могут соответствовать подстрокам нулевой длины. Вот простой пример:
@chars = split //, $string; # // is not magic in split
($whitewashed = $string) =~ s/()/ /g; # parens avoid magic s// / Таким образом, Perl позволяет такие конструкции, принудительно прерывая бесконечный цикл. Правила для этого отличаются для циклов нижнего уровня, заданных жадными квантификаторами *+{}, и для циклов высшего уровня, таких как модификатор /g или оператор split().
Циклы нижнего уровня прерываются (то есть цикл прерывается) при обнаружении Perl, что повторяющееся выражение соответствует подстроке нулевой длины. Таким образом
m{ (?: NON_ZERO_LENGTH | ZERO_LENGTH )* }x; эквивалентно
m{ (?: NON_ZERO_LENGTH )* (?: ZERO_LENGTH )? }x; Например, эта программа
#!perl -l
"aaaaab" =~ /
(?:
a # non-zero
| # or
(?{print "hello"}) # print hello whenever this
# branch is tried
(?=(b)) # zero-width assertion
)* # any number of times
/x;
print $&;
print $1; выводит
hello
aaaaa
b Обратите внимание, что "hello" выводится только один раз, так как при обнаружении Perl, что шестая итерация внешнего (?:)* соответствует строке нулевой длины, она останавливает "*".
Циклы высшего уровня сохраняют дополнительное состояние между итерациями: была ли последняя совпадение нулевой длины. Чтобы прервать цикл, последующее совпадение после совпадения нулевой длины не должно иметь нулевой длины. Это ограничение взаимодействует с возвратом назад (см. "Обратный поиск"), поэтому выбирается второе по лучшинству совпадение, если лучшее совпадение имеет нулевую длину.
Например:
$_ = 'bar';
s/\w??/<$&>/g; приводит к <><b><><a><><r><>. В каждой позиции строки лучшим совпадением, заданным нежадным ??, является совпадение нулевой длины, и второе по лучшинству совпадение — это то, что соответствует \w. Таким образом, совпадения нулевой длины чередуются с совпадениями длиной в один символ.
Аналогично, для повторяющегося m/()/g вторым по лучшинству совпадением является совпадение в позиции на один шаг дальше в строке.
Дополнительное состояние, являющееся совпадением нулевой длины, ассоциируется с сопоставленной строкой и сбрасывается при каждом присваивании pos(). Совпадения нулевой длины в конце предыдущего совпадения игнорируются во время split.
Объединение элементов регулярных выражений
Каждый из элементарных фрагментов регулярных выражений, описанных ранее (таких как ab или \Z ), может соответствовать не более чем одной подстроке в заданной позиции входной строки. Однако в типичном регулярном выражении эти элементарные фрагменты объединяются в более сложные шаблоны с помощью операторов объединения ST, S|T, S* и т. д. (в этих примерах "S" и "T" являются регулярными подвыражениями).
Такие комбинации могут включать альтернативы, что приводит к проблеме выбора: если мы сопоставляем регулярное выражение a|ab с "abc", будет ли оно соответствовать подстроке "a" или "ab"? Один из способов описания подстроки, которая фактически совпадает, — понятие обратного поиска (см. "Обратный поиск"). Однако это описание слишком низкого уровня и заставляет вас думать в терминах конкретной реализации.
Другое описание начинается с понятий «лучше»/«хуже». Все подстроки, которые могут соответствовать данному регулярному выражению, можно отсортировать от «лучшего» совпадения к «худшему» совпадению, и выбирается «лучшее» совпадение. Это заменяет вопрос «что выбирается?» вопросом «какие совпадения лучше, а какие хуже?».
Опять же, для элементарных фрагментов такого вопроса нет, так как возможно не более одного совпадения в данной позиции. В этом разделе описывается понятие «лучше»/«хуже» для операторов объединения. В описании ниже "S" и "T" — это регулярные подвыражения.
ST-
Рассмотрим два возможных совпадения,
ABиA'B',"A"иA'— это подстроки, которые могут соответствовать"S","B"иB'— это подстроки, которые могут соответствовать"T".Если
"A"— лучшее совпадение для"S"по сравнению сA', тоAB— лучшее совпадение, чемA'B'.Если
"A"иA'совпадают:AB— лучшее совпадение, чемAB'если"B"— лучшее совпадение для"T"по сравнению сB'. -
S|T -
Если
"S"может соответствовать, то это лучшее совпадение, чем только"T"может соответствовать.Порядок двух совпадений для
"S"такой же, как и для"S". Аналогично для двух совпадений для"T". -
S{REPEAT_COUNT} -
Соответствует
SSS...S(повторяется столько раз, сколько необходимо). -
S{min,max} -
Соответствует
S{max}|S{max-1}|...|S{min+1}|S{min}. -
S{min,max}? -
Соответствует
S{min}|S{min+1}|...|S{max-1}|S{max}. -
S?,S*,S+ -
То же, что и
S{0,1},S{0,BIG_NUMBER},S{1,BIG_NUMBER}соответственно. -
S??,S*?,S+? -
То же, что и
S{0,1}?,S{0,BIG_NUMBER}?,S{1,BIG_NUMBER}?соответственно. -
(?>S) -
Соответствует лучшему совпадению для
"S"и только ему. -
(?=S),(?<=S) -
Рассматривается только лучшее совпадение для
"S". (Это важно только если у"S"есть группирующие скобки и где-то еще в регулярном выражении используются обратные ссылки.) -
(?!S),(?<!S) -
Для этого оператора группирования нет необходимости описывать порядок, так как важен только факт, может ли
"S"соответствовать или нет. -
(??{ EXPR }),(?PARNO) -
Порядок такой же, как и для регулярного выражения, которое является результатом EXPR, или шаблона, содержащегося в группе захвата PARNO.
-
(?(condition)yes-pattern|no-pattern) -
Вспомните, какой из yes-pattern или no-pattern фактически соответствует, уже определено. Порядок совпадений такой же, как и для выбранного подвыражения.
Вышеупомянутые рецепты описывают порядок совпадений в данной позиции. Еще одно правило необходимо для понимания того, как определяется совпадение для всего регулярного выражения: совпадение в более ранней позиции всегда лучше, чем совпадение в более поздней позиции.
Создание собственных движков регулярных выражений
Начиная с Perl 5.10.0, можно создавать собственные движки регулярных выражений. Это не для слабонервных, так как они должны подключаться на уровне C. Подробнее см. perlreapi.
В качестве альтернативы перегруженные константы (см. overload) предоставляют простой способ расширения функциональности движка регулярных выражений, заменяя один шаблон другим.
Предположим, что мы хотим включить новый escape-последовательность RE \Y| , которая соответствует границе между символами пробелов и несимволами пробелов. Обратите внимание, что (?=\S)(?<!\S)|(?!\S)(?<=\S) соответствует именно этим позициям, поэтому мы хотим, чтобы каждое \Y| заменяло более сложную версию. Мы можем создать модуль customre для этого:
package customre;
use overload;
sub import {
shift;
die "No argument to customre::import allowed" if @_;
overload::constant 'qr' => \&convert;
}
sub invalid { die "/$_[0]/: invalid escape '\\$_[1]'"}
# We must also take care of not escaping the legitimate \\Y|
# sequence, hence the presence of '\\' in the conversion rules.
my %rules = ( '\\' => '\\\\',
'Y|' => qr/(?=\S)(?<!\S)|(?!\S)(?<=\S)/ );
sub convert {
my $re = shift;
$re =~ s{
\\ ( \\ | Y . )
}
{ $rules{$1} or invalid($re,$1) }sgex;
return $re;
} Теперь use customre включает новый escape в постоянных регулярных выражениях, т. е., без каких-либо интерполяций переменных во время выполнения. Как описано в overload, эта конвертация будет работать только над буквальными частями регулярных выражений. Для \Y|$re\Y| переменная часть этого регулярного выражения должна быть преобразована явно (но только если специальное значение \Y| должно быть включено внутри $re):
use customre;
$re = <>;
chomp $re;
$re = customre::convert $re;
/\Y|$re\Y|/; Частота выполнения встроенного кода
Точные правила о том, как часто (??{}) и (?{}) выполняются в шаблоне, не определены. В случае успешного совпадения можно предположить, что они будут работать «автоматически» и будут выполняться слева направо соответствующее количество раз в принимающей ветви шаблона, как и любой другой мета-шаблон. То, как неакцептируемые ветви и ошибки сопоставления влияют на количество раз, когда выполняется шаблон, специально не определено и может меняться в зависимости от применяемых оптимизаций шаблона, а также, вероятно, будет меняться от версии к версии.
Например, в
"aaabcdeeeee"=~/a(?{print "a"})b(?{print "b"})cde/; точное количество раз, когда «a» или «b» выводятся при ошибке, не определено, но можно предположить, что они будут выведены по крайней мере один раз во время успешного совпадения, и, кроме того, можно предположить, что если «b» выводится, ему будет предшествовать по крайней мере одно «a».
В случае ветвящихся конструкций, таких как следующие:
/a(b|(?{ print "a" }))c(?{ print "c" })/; можно предположить, что ввод "ac" выведет "ac", а "abc" выведет только "c".
При квантификации встроенного кода успешные совпадения вызовут код один раз для каждой совпадающей итерации квантификатора. Например:
"good" =~ /g(?:o(?{print "o"}))*d/; выведет "o" дважды.
Поддержка PCRE/Python
Начиная с Perl 5.10.0, Perl поддерживает несколько расширений синтаксиса регулярных выражений Python/PCRE. Хотя программистам Perl рекомендуется использовать Perl-специфичный синтаксис, следующие также принимаются:
-
(?P<NAME>pattern) -
Определить именованную группу захвата. Эквивалентно
(?<NAME>pattern). -
(?P=NAME) -
Обратная ссылка на именованную группу захвата. Эквивалентно
\g{NAME}. -
(?P>NAME) -
Вызов подпрограммы к именованной группе захвата. Эквивалентно
(?&NAME).
ОШИБКИ
Существует ряд проблем с учетом регистра при сопоставлении с Unicode-правилами. См. "i" в разделе "Модификаторы" выше.
Данный документ варьируется от сложного для понимания до совершенно непрозрачного. Блуждающая проза, насыщенная терминологией, в нескольких местах трудно поддаётся осмыслению.
Этот документ требует переработки, разделяя учебный контент от справочного.
СМОТРИТЕ ТАКЖЕ
Синтаксис шаблонов, используемых в Perl для сопоставления с образцом, эволюционировал из синтаксиса, предоставленного в программных средствах для регулярных выражений Bell Labs Research Unix 8-го издания (версия 8). (Код фактически получен (косвенно) от свободно распространяемой переработки Генри Спенсера этих процедур V8.)
"Операторы цитирования регулярных выражений" в perlop.
"Подробные сведения о разборе цитированных конструкций" в perlop.
Мастерство регулярных выражений Джеффри Фридла, издательство O'Reilly and Associates.
© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.30.3/perlre