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 (ord 255/256), не будут успешными, если расположение не является UTF-8. См. perllocale.
Существует ряд символов Unicode, которые сопоставляются с последовательностью нескольких символов в
/i. Например,LATIN SMALL LIGATURE FIдолжно сопоставляться с последовательностьюfi."\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 в настоящее время не может сделать это, когда несколько символов находятся в шаблоне и разделены группами, или когда один или несколько из них имеют квантификатор. Таким образом
"\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{} или \p{name=...} экранирования. Бесполезно пытаться продолжить комментарий на следующую строку, экранировав \n с обратным слэшем или \Q.
Вы можете использовать "(?#текст)" для создания комментария, который заканчивается раньше, чем конец текущей строки, но 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 устанавливает набор символов в соответствии с тем, что 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 чтобы получить правила Юникода, так как \L в первом случае (но не обязательно во втором) также будут использовать правила Юникода.
Более подробная информация о каждом из модификаторов приведена ниже. Скорее всего, вам не нужно знать эти подробности для /l, /u, и /d, и вы можете перейти к /a.
/l
означает использование правил текущего локали (см. perllocale) при сопоставлении шаблонов. Например, \w будет соответствовать символам «слова» этого локали, а "/i" будет выполнять сопоставление без учёта регистра в соответствии с правилами сгибания регистра локали. Использованный локал будет тем, который действует в момент выполнения сопоставления шаблона. Он может не совпадать с локалем времени компиляции и может отличаться от одного сопоставления к другому, если между ними выполняется вызов функции setlocale().
До версии v5.20 Perl не поддерживал многобайтовые локали. Начиная с этой версии, поддерживаются локали UTF-8. Скорее всего, другие многобайтовые локали никогда не будут поддерживаться. Однако во всех локалях могут быть символы с кодами выше 255, и они всегда будут обрабатываться как символы Юникода независимо от действующего локали.
В соответствии с правилами Юникода существует несколько сопоставлений без учёта регистра, которые пересекают границу 255/256. За исключением локалей UTF-8 в Perls версии 5.20 и выше, они запрещены в /l. Например, 0xFF (на платформах ASCII) не соответствует символу с кодом 0x178 без учёта регистра, LATIN CAPITAL LETTER Y WITH DIAERESIS, потому что 0xFF может не быть LATIN SMALL LETTER Y WITH DIAERESIS в текущем локали, и Perl не может знать, существует ли этот символ в локали, и тем более, какой код символа ему соответствует.
В локали UTF-8 в версиях 5.20 и выше единственное заметное различие между локали и не-локалью в регулярных выражениях должно быть связано с заражением (см. perlsec).
Этот модификатор может быть указан в качестве значения по умолчанию use locale, но см. "Какой модификатор набора символов действует?".
/u
означает использование правил Юникода при сопоставлении шаблонов. На платформах ASCII это означает, что символы с кодами от 128 до 255 принимают свои значения Latin-1 (ISO-8859-1) (которые совпадают со значениями Юникода). (В противном случае Perl считает их значения неопределёнными.) Таким образом, при этом модификаторе платформа ASCII фактически становится платформой Юникода; и поэтому, например, \w будет соответствовать любому из более чем 100 000 символов «слов» в Юникоде.
В отличие от большинства локалей, которые специфичны для пары язык-страна, Юникод классифицирует все символы, которые являются буквами где-либо в мире, как \w. Например, ваш локал может не считать, что LATIN SMALL LETTER ETH является буквой (если вы не случайно говорите по-исландецки), но Юникод считает. Аналогично, все символы, являющиеся десятичными цифрами где-либо в мире, будут соответствовать \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.
Кроме того, при этом модификаторе сопоставление без учёта регистра работает со всем набором символов Юникода. Например, KELVIN SIGN соответствует буквам «k» и «K»; а LATIN SMALL LIGATURE FF соответствует последовательности «ff», что, если вы не готовы, может заставить вас подумать, что это шестнадцатеричная константа, создавая ещё одну потенциальную проблему безопасности. Более подробная информация о проблемах безопасности Юникода приведена по адресу https://unicode.org/reports/tr36.
Этот модификатор может быть указан в качестве значения по умолчанию use feature 'unicode_strings, use locale ':not_characters', или use 5.012 (или выше), но см. "Какой модификатор набора символов действует?".
/d
Этот модификатор означает использование «умолчательных» собственных правил платформы, за исключением случаев, когда необходимо использовать правила Юникода, как указано ниже:
-
целевая строка закодирована в UTF-8; или
-
шаблон закодирован в UTF-8; или
-
в шаблоне явно упоминается символ с кодом выше 255 (скажем,
\x{100}); или -
в шаблоне указано имя символа Юникода (
\N{...}); или -
в шаблоне указано свойство Юникода (
\p{...}или\P{...}); или -
в шаблоне используется разрыв Юникода (
\b{...}или\B{...}); или -
в шаблоне используется "
(?[ ])" -
в шаблоне используется
(*script_run: ...)
Ещё одним мнемоническим обозначением для этого модификатора является «Зависит», так как используемые правила фактически зависят от различных факторов, и в результате вы можете получить неожиданные результаты. См. "Ошибка Юникода" в perlunicode. Ошибка Юникода стала довольно известной, что привело к ещё одному (не ругаясь) названию для этого модификатора — «Ненадёжный».
Если шаблон или строка не закодированы в 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, до Юникода. При /a, \d всегда означает точно цифры "0" до "9"; \s означает пять символов [ \f\n\r\t], а начиная с Perl v5.18, вертикальную вкладку; \w означает 63 символа [A-Za-z0-9_]; и аналогично, все классы Posix, такие как [[:print:]] соответствуют только соответствующим символам ASCII.
Этот модификатор полезен для людей, которые случайно используют Юникод и не хотят быть обременёнными его сложностями и проблемами безопасности.
С помощью /a, можно написать \d с уверенностью, что он будет соответствовать только символам ASCII, и если возникнет необходимость сопоставить символы за пределами ASCII, можно вместо этого использовать \p{Digit} (или \p{Word} для \w). Существуют аналогичные \p{...} конструкции, которые могут сопоставлять символы за пределами ASCII, как пробелы (см. "Пробелы" в perlrecharclass), и классы Posix (см. "Классы символов Posix" в perlrecharclass). Таким образом, этот модификатор не означает, что вы не можете использовать Юникод, он означает, что для получения соответствия Юникоду необходимо явно использовать конструкцию (\p{}, \P{}) которая указывает на Юникод.
Как можно было ожидать, этот модификатор заставляет, например, \D означать то же самое, что и [^0-9]; фактически, все не-ASCII символы соответствуют \D, \S, и \W. \b по-прежнему означает сопоставление на границе между \w и \W, используя определения /a (аналогично для \B).
В противном случае, /a ведёт себя как модификатор /u, при этом сопоставление без учёта регистра использует правила Юникода; например, «k» будет соответствовать Юникоду \N{KELVIN SIGN} при сопоставлении без учёта регистра, а символы в диапазоне Latin1, расположенные выше ASCII, будут иметь правила Юникода, когда речь идёт о сопоставлении без учёта регистра.
Чтобы запретить соответствия ASCII/не-ASCII (например, «k» с \N{KELVIN SIGN}), укажите "a" дважды, например, /aai или /aia. (Первый символ "a" ограничивает \d, и т. д., а второй символ добавляет /i ограничения.) Но обратите внимание, что символы с кодами за пределами диапазона ASCII будут использовать правила Юникода для сопоставления /i, поэтому этот модификатор фактически не ограничивает всё только ASCII; он просто запрещает смешивание ASCII и не-ASCII.
Подводя итог, этот модификатор обеспечивает защиту для приложений, которые не хотят быть подвержены воздействию всего Юникода. Указание его дважды даёт дополнительную защиту.
Этот модификатор может быть установлен в качестве значения по умолчанию use re '/a' или use re '/aa'. Если вы это сделаете, у вас может возникнуть необходимость явно использовать модификатор /u если есть несколько регулярных выражений, где вы хотите полные правила Юникода (но даже и здесь лучше, если всё было бы под управлением функции "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 Подробности см. в "Операторы кавычек и похожие на кавычки" в perlop.
Классы символов и другие специальные escapes
Кроме того, 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]
-
Подробности см. в "Классы символов в квадратных скобках" в perlrecharclass.
- [2]
-
Подробности см. в "Классы символов POSIX" в perlrecharclass.
- [3]
-
Подробности см. в "Свойства символов Юникода" в perlunicode
- [4]
-
Подробности см. в "Разное" в perlrebackslash.
- [5]
-
Подробности см. в "Группы захвата" ниже.
- [6]
-
Подробности см. в "Расширенные шаблоны" ниже.
- [7]
-
Обратите внимание, что
\Nимеет два значения. Когда он имеет вид\N{NAME}, он соответствует символу или последовательности символов, имя которого NAME; и аналогично, когда он имеет вид\N{U+hex}, он соответствует символу с кодом Юникода hex. В противном случае он соответствует любому символу, кроме\n. - [8]
-
Подробности см. в "Расширенные классы символов в квадратных скобках" в 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), как описано в "Операторы кавычек и похожие на кавычки для регулярных выражений" в perlop. Оно также полезно при написании сканеров типа lex, когда у вас есть несколько шаблонов, которые вы хотите сопоставить с последующими подстроками вашей строки; см. предыдущую ссылку. Фактическое место, где \G будет совпадать, также может быть изменено с использованием pos() в качестве lvalue: см. "pos" в perlfunc. Обратите внимание, что правило для совпадений нулевой длины (см. "Повторные шаблоны, сопоставляющие подстроку нулевой длины") несколько изменено, в том смысле, что содержимое слева от \G не учитывается при определении длины совпадения. Таким образом, следующее не будет совпадать бесконечно:
my $string = 'ABC';
pos($string) = 1;
while ($string =~ /(.\G)/g) {
print $1;
} Это выведет 'A' и затем завершится, поскольку считает совпадение нулевой длины и, следовательно, не будет совпадать в одном и том же месте дважды подряд.
Стоит отметить, что \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 — backspace). 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" в 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. - Утверждения поиска вокруг
-
Утверждения с опережающим просмотром — это шаблоны нулевой ширины, которые соответствуют определённому шаблону без включения его в
$&. Положительные утверждения соответствуют, когда их подшаблон соответствует, отрицательные утверждения соответствуют, когда их подшаблон не соответствует. Опережающий просмотр назад соответствует тексту до текущей позиции совпадения, опережающий просмотр вперёд соответствует тексту после текущей позиции совпадения.-
(?=pattern) -
(*pla:pattern) -
(*positive_lookahead:pattern) -
Утверждение с положительным опережающим просмотром нулевой ширины. Например,
/\w+(?=\t)/соответствует слову, за которым следует табуляция, без включения табуляции в$&. -
(?!pattern) -
(*nla:pattern) -
(*negative_lookahead:pattern) -
Утверждение с отрицательным опережающим просмотром нулевой ширины. Например,
/foo(?!bar)/соответствует любому вхождению "foo", за которым не следует "bar". Однако обратите внимание, что опережающий просмотр вперёд и назад — это НЕ одно и то же. Вы не можете использовать это для опережающего просмотра назад.Если вы ищете "bar", за которым не следует "foo",
/(?!foo)bar/не сделает того, что вы хотите. Это потому, что(?!foo)просто говорит, что следующее не может быть "foo" — а это не так, это "bar", поэтому "foobar" будет соответствовать. Используйте опережающий просмотр назад (см. ниже). -
(?<=pattern) -
\K -
(*plb:pattern) -
(*positive_lookbehind:pattern) -
Утверждение с положительным опережающим просмотром назад нулевой ширины. Например,
/(?<=\t)\w+/соответствует слову, за которым следует табуляция, без включения табуляции в$&.До Perl 5.30 он работал только с опережающим просмотром назад фиксированной ширины, но начиная с этой версии он может обрабатывать переменную длину от 1 до 255 символов как экспериментальную функцию. Эта функция включается автоматически при использовании утверждения опережающего просмотра назад переменной длины, но будет выводить предупреждение во время компиляции шаблона, если она не выключена, в категории
experimental::vlb. Это предупреждение о том, что точное поведение может измениться, если обратная связь от реального использования в поле укажет на это; или даже полное удаление, если обнаруженные проблемы не могут быть практически решены. Вы можете добиться поведения, близкого к поведению до 5.30, приведя к предупреждению в этой категории к ошибке.Существует специальная форма этого конструктора, называемая
\K(доступная с Perl 5.10.0), которая заставляет движок регулярных выражений «сохранять» всё, что он сопоставил до\Kи не включать его в$&. Это эффективно обеспечивает опережающий просмотр назад переменной длины любой длины.И существует техника, которая может быть использована для обработки опережающего просмотра назад переменной длины в более ранних выпусках и более 255 символов. Она описана в http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html.
Обратите внимание, что в
/i, несколько отдельных символов соответствуют двум или трём другим символам. Это делает их переменной длиной, а длина 255 относится к максимальному числу символов в совпадении. Например,qr/\N{LATIN SMALL LETTER SHARP S}/iсоответствует последовательности"ss". Ваше утверждение опережающего просмотра назад может содержать 127 символов Sharp S в/i, но добавление 128-го вызовет ошибку компиляции, так как это может соответствовать 256"s"символам подряд.Использование
\Kвнутри другого утверждения опережающего просмотра разрешено, но поведение в настоящее время не определено.По различным причинам
\Kможет быть значительно эффективнее, чем эквивалентный конструктор(?<=...), и он особенно полезен в ситуациях, когда вы хотите эффективно удалить что-то, что следует за чем-то другим в строке. Напримерs/(foo)bar/$1/g;может быть переписан как гораздо более эффективный
s/foo\Kbar//g;Использование модификатора нежадного соответствия
"?"может не дать ожидаемых результатов, если он находится внутри группы захвата в конструкторе. -
(?<!pattern) -
(*nlb:pattern) -
(*negative_lookbehind:pattern) -
Утверждение с отрицательным опережающим просмотром назад нулевой ширины. Например,
/(?<!bar)foo/соответствует любому вхождению "foo", за которым не следует "bar".До Perl 5.30 он работал только с опережающим просмотром назад фиксированной ширины, но начиная с этой версии он может обрабатывать переменную длину от 1 до 255 символов как экспериментальную функцию. Эта функция включается автоматически при использовании утверждения опережающего просмотра назад переменной длины, но будет выводить предупреждение во время компиляции шаблона, если она не выключена, в категории
experimental::vlb. Это предупреждение о том, что точное поведение может измениться, если обратная связь от реального использования в поле укажет на это; или даже полное удаление, если обнаруженные проблемы не могут быть практически решены. Вы можете добиться поведения, близкого к поведению до 5.30, приведя к предупреждению в этой категории к ошибке.Существует техника, которая может быть использована для обработки опережающего просмотра назад переменной длины в более ранних выпусках и более 255 символов. Она описана в http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html.
Обратите внимание, что в
/i, несколько отдельных символов соответствуют двум или трём другим символам. Это делает их переменной длиной, а длина 255 относится к максимальному числу символов в совпадении. Например,qr/\N{LATIN SMALL LETTER SHARP S}/iсоответствует последовательности"ss". Ваше утверждение опережающего просмотра назад может содержать 127 символов Sharp S в/i, но добавление 128-го вызовет ошибку компиляции, так как это может соответствовать 256"s"символам подряд.Использование модификатора нежадного соответствия
"?"может не дать ожидаемых результатов, если он находится внутри группы захвата в конструкторе.
-
-
(?<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, можно использовать шаблон
(?P<NAME>pattern)вместо(?<NAME>pattern); однако эта форма не поддерживает использование одинарных кавычек в качестве разделителя для имени. -
\k<NAME> -
\k'NAME' -
Именованная ссылка на обратный ссылочный шаблон. Аналогично числовым ссылкам на обратные ссылочные шаблоны, за исключением того, что группа обозначается именем, а не номером. Если несколько групп имеют одинаковое имя, то оно ссылается на самую левую определённую группу в текущем совпадении.
Ошибка, если ссылаться на имя, не определённое
(?<NAME>)ранее в шаблоне.Обе формы эквивалентны.
ПРИМЕЧАНИЕ: Для облегчения работы программистам, знакомым с движками регулярных выражений Python или PCRE, можно использовать шаблон
(?P=NAME)вместо\k<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', вы также должны включить проверку на загрязнение. Еще лучше использовать тщательно ограниченное вычисление в отсеке Safe. Подробности об этих механизмах см. в 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)переключателе. Если оно не используется таким образом, результат вычисления 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-pattern никогда не выполняется напрямую, и no-pattern не разрешается. Подобно по духу
(?{0}), но более эффективно. Подробности см. ниже. Полный синтаксис:(?(DEFINE)definitions...)
Например:
m{ ( \( )? [^()]+ (?(1) \) ) }xсоответствует фрагменту без скобок, возможно, включённому в сами скобки.
Особой формой является предикат
(DEFINE), который никогда не выполняет свой yes-pattern напрямую и не допускает no-pattern. Это позволяет определить подшаблоны, которые будут выполняться только механизмом рекурсии. Таким образом, вы можете определить набор правил регулярных выражений, которые можно объединить в любой выбранный вами шаблон.Рекомендуется для этого использования помещать блок 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) -
«Независимое» подвыражение, которое соответствует подстроке, которую бы сопоставил автономный шаблон, если бы он был привязан к данному положению, и оно соответствует только этой подстроке. Этот конструкт полезен для оптимизации того, что в противном случае были бы «вечными» соответствиями, потому что он не будет возвращаться назад (см. «Возврат назад»). Он также может быть полезен в местах, где желательна семантика «захват всех возможных вариантов и возврат ничего».
Например:
^(?>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)/не соответствует.
-
(?[ ]) -
См. "Расширенные символьные классы" в 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) После того, как шаблон успешно сопоставился, он дополнительно проверяется на соответствие условию, что каждый символ в нём должен быть из одного и того же набора символов (см. исключения ниже). Если это не так, происходит возврат назад, пока не будет найдено что-то, что полностью соответствует одному набору символов, или пока не будут исчерпаны все возможности. Это может привести к большому количеству возвратов назад, но, как правило, только вредоносный ввод приведёт к этому, хотя замедление может привести к атаке типа отказа в обслуживании. Если ваши потребности позволяют, лучше сделать шаблон атомарным, чтобы сократить количество возвратов назад. Это так вероятно, что вы хотите этого, что вместо написания этого:
(*script_run:(?>pattern)) Вы можете написать что-то из этого:
(*atomic_script_run:pattern)
(*asr:pattern) (См. "(?>pattern)".)
В Тайване, Японии и Корее распространён текст, содержащий смесь символов из их родных наборов символов и базового китайского языка. Perl следует стандарту Unicode UTS 39 (https://unicode.org/reports/tr39/) в отношении механизмов безопасности Unicode, разрешая такие смеси. Например, японские наборы символов катакана и хирагана обычно смешиваются вместе на практике, наряду с некоторыми китайскими символами, и поэтому Perl обрабатывает их как единый набор символов.
Правила, используемые для сопоставления десятичных цифр, несколько строже. Многие наборы символов имеют свои собственные наборы цифр, эквивалентные западным 0 по 9. Некоторые, такие как арабские, имеют более одного набора. Чтобы строка считалась набором символов, все цифры в ней должны быть из одного и того же набора из десяти, как определяется первой встретившейся цифрой. Например,
qr/(*script_run: \d+ \b )/x гарантирует, что сопоставленные цифры будут из одного и того же набора из десяти. Вы не получите подобную цифру из другого набора символов, имеющую другое значение, чем кажется.
Unicode имеет три псевдо-набора символов, которые обрабатываются специально.
«Неизвестный» применяется к кодовым точкам, значение которых ещё не определено. Perl в настоящее время будет сопоставлять как набор символов любую строку символов длиной в один символ, состоящую из одной из этих кодовых точек. Однако любая строка символов длиной более одного символа, содержащая одну из них, не будет считаться набором символов.
«Наследуемый» применяется к символам, которые изменяют другой символ, например, к какому-либо типу диакритического знака. Они считаются принадлежащими набору символов основного символа и, следовательно, никогда не препятствуют совпадению с набором символов.
Другой — «Общие». Он в основном состоит из знаков препинания, эмодзи и символов, используемых в математике и музыке, а также ASCII-цифр 0 по 9, и полных форм этих цифр. Эти символы могут встречаться смешанно в текстах многих языковых наборов мира. Они также не препятствуют совпадению с набором символов. Но, как и в других наборах символов, все цифры в наборе должны быть из одного и того же набора из десяти.
Этот конструкт является незахватывающим. Вы можете добавить скобки к шаблону для захвата, если хотите. Вам придётся сделать это, если вы планируете использовать "(*ACCEPT) (*ACCEPT:arg)" и не хотите, чтобы это минуло проверку набора символов.
Свойство Script_Extensions, изменённое в UTS 39 (https://unicode.org/reports/tr39/), используется в качестве основы для этой функции.
В качестве резюме,
-
Все последовательности длиной 0 или 1 являются наборами символов.
-
Более длинная последовательность является набором символов тогда и только тогда, когда все следующие условия выполнены:
-
Ни одна кодовая точка в последовательности не имеет свойства
Script_ExtensionUnknown.
Это в настоящее время означает, что все кодовые точки в последовательности были назначены Unicode как символы, не являющиеся символами частного использования или суррогатными кодовыми точками. -
Все символы в последовательности берутся из набора «Общие» и/или «Наследуемые» и/или одного другого набора символов.
Набор символов символа определяется свойствомScript_Extensions, изменённым в UTS 39 (https://unicode.org/reports/tr39/), как описано выше. -
Все десятичные цифры в последовательности берутся из одного и того же блока из 10 последовательных цифр.
-
Специальные команды управления возвратом
Эти специальные шаблоны обычно имеют вид (*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) -
Это аналогично оператору «группы вырезки»
::из Raku. Как и(*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) -
Это раку «шаблон фиксации»
<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) обеспечивают простой способ расширения функциональности движка регулярных выражений путём подстановки одного шаблона на другой.
Предположим, что мы хотим включить новую последовательность экранирования 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 включает новое экранирование в постоянных регулярных выражениях, т.е., в тех, которые не содержат никаких интерполяций переменных во время выполнения. Как документировано в 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). (Код фактически получен (далеким родственником) от свободно распространяемой переработки Henry Spencer этих процедур 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.32.0/perlre