非常教程

Erlang 20参考手册

stdlib

re

模块

Re

模块摘要

Erlang的类Perl正则表达式。

描述

该模块包含字符串和二进制文件的正则表达式匹配函数。

regular expression语法和语义类似于Perl 的语法和语义。

该库的匹配算法基于PCRE库,但不是所有的PCRE库都是连接的,并且库的某些部分超出了PCRE提供的范围。目前使用PCRE版本8.40(发布日期2017-01-11)。这里包含了与该模块相关的PCRE文档部分。

字符串的Erlang文字语法使用“\”(反斜线)字符作为转义码。你需要在你的代码和shell中用文字字符串转义反斜杠,并加上一个额外的反斜杠,即“\”。

数据类型

mp() = {re_pattern, term(), term(), term(), term()}

包含已编译的正则表达式的不透明数据类型。mp()保证是一个以原子re_pattern作为第一个元素的 tuple() ,以便在守卫中进行匹配。未来的Erlang/OTP版本中元组的元素或其他字段的内容可能会发生变化。

nl_spec() = cr | crlf | lf | anycrlf | any

compile_option() =

unicode |

anchored |

caseless |

dollar_endonly |

dotall |

extended |

firstline |

multiline |

no_auto_capture |

dupnames |

ungreedy |

{newline,nl_spec()} |

bsr_anycrlf |

bsr_unicode |

no_start_optimize |

ucp |

never_utf

出口

version() -> binary()

此函数的返回是一个字符串,其中包含Erlang/OTP编译中使用的系统的PCRE版本。

compile(Regexp) -> {ok, MP} | {error, ErrSpec}

类型

compile(Regexp,[])

compile(Regexp, Options) -> {ok, MP} | {error, ErrSpec}

类型

使用下面描述的语法将正则表达式编译为内部格式,稍后将其用作参数to run/2run/3

如果在程序的生命周期中使用相同的表达式来匹配多个主题,则在匹配之前编译正则表达式非常有用。编译一次并执行多次比每次想要匹配的编译效率高得多。

unicode指定选项时,正则表达式将被指定为有效的Unicode charlist(),否则为任何有效的iodata()

备选方案:

unicode

正则表达式被指定为Unicode charlist(),并且生成的正则表达式代码将针对有效的Unicode charlist()主题运行。ucp在使用Unicode字符时还要考虑选项。

anchored

该模式被强制为“锚定”,也就是说,它仅限于匹配搜索字符串中的第一个匹配点(“主题字符串”)。这种效应也可以通过模式本身的适当构造来实现。

caseless

模式中的字母匹配大写和小写字母。它相当于Perl选项/i,可以通过(?i)选项设置在模式内进行更改。大写和小写字母在ISO 8859-1字符集中定义。

dollar_endonly

模式中的美元元字符仅在主题字符串的末尾匹配。如果没有这个选项,一美元也会在字符串末尾的换行符之前立即匹配(但不会在任何其他换行符之前)。如果multiline指定了选项,则忽略此选项。在Perl中没有相应的选项,它不能在模式中设置。

dotall

模式中的一个点匹配所有字符,包括那些指示换行符的字符。如果没有它,当前位置位于换行符时,点不匹配。这个选项相当于Perl选项/s,它可以通过(?s)选项设置在模式内进行更改。负面的类,例如[^a]总是匹配换行符,独立于此选项的设置。

extended

如果设置了此选项,则除了转义或字符类内部以外,模式中的大多数空白字符都会被完全忽略。但是,在(?>引入各种括号内的子模式的序列中不允许使用空格,也不能使用数字量词{1,3}。然而,在项目和后面的量词之间以及在量词和后面的+之间允许可以忽略的空白,表示所有格。

白色空间并未用于包含VT字符(代码11),因为Perl并未将此字符视为空白字符。但是,Perl在版本5.18中进行了更改,因此PCRE随后在版本8.34中,VT现在被视为空白。

这也会导致字符类之外的未转义#与下一个包含换行符的字符之间的字符被忽略。这相当于Perl的/x选项,它可以通过(?x)选项设置在模式内进行更改。

使用此选项,可以包含复杂模式中的注释。但是请注意,这仅适用于数据字符。空格字符不能出现在模式中的特殊字符序列中,例如在(?(引入条件子模式的序列内。

firstline

在主题字符串的第一个换行符之前或之前,需要使用未锚定的模式进行匹配,但匹配的文本可以在换行符上继续。

multiline

默认情况下,PCRE将主题字符串视为由单行字符组成(即使它包含换行符)。“行首”metacharacter(^)只匹配字符串的起始位置,而“行尾”metacharacter($)只匹配字符串末尾或终止换行符(除非dollar_endonly指定了选项)。这与Perl中的相同。

当指定此选项时,“起始行”和“行结束”构造分别与主题字符串中的内部换行符之后或之前匹配,以及最开始和结束时匹配。这相当于Perl选项/m,可以通过(?m)选项设置在模式内进行更改。如果有目标字符串没有换行符,或者没有出现的^或者$在一个模式,设置multiline没有任何效果。

no_auto_capture

禁用模式中使用编号的捕获括号。没有遵循的任何开头括号的?行为就好像跟着一样?:。命名的圆括号仍然可以用于捕获(并以通常的方式获取数字)。Perl中没有相应的选项。

dupnames

用于识别捕获子模式的名称不必是唯一的。当知道只有命名子模式的一个实例可以匹配时,这可能对某些类型的模式有帮助。下面提供了命名子模式的更多细节。

ungreedy

颠倒量词的“贪婪”,使它们在默认情况下不会贪婪,但如果后面跟着“?”则变得贪婪。它与Perl不兼容。它也可以通过模式中的(?U)选项设置进行设置。

{newline, NLSpec}

覆盖主题字符串中的换行符的默认定义,即Erlang中的LF(ASCII 10)。

cr

换行符由单个字符cr(ASCII 13)表示。

lf

换行符由单个字符LF(ASCII 10)表示,默认值为。

crlf

换行符由双字符CRLF(ASCII 13和ASCII 10)序列表示。

anycrlf

前三个序列中的任何一个都将被识别。

any

以上任何一种换行符序列和Unicode序列VT(垂直制表符,U + 000B),FF(换页符,U + 000C),NEL(下一行,U + 0085),LS(行分隔符,U + 2028)和PS(段落分隔符,U + 2029)。

**`bsr_anycrlf`**  

具体指定\R仅匹配CR,LF或CRLF序列,而不是特定于Unicode的换行符。

bsr_unicode

具体指定\R将匹配所有Unicode换行符(包括CRLF,等等,默认值)。

no_start_optimize

如果正则表达式中存在“特殊图案开始项目”,则禁用可能发生故障的优化。一个典型的例子是将“DEFABC”与“(* COMMIT)ABC”相匹配,其中PCRE的开始优化将跳过主题直到“A”,并且永远不会意识到(* COMMIT)指令将进行匹配失败。如果您使用“模式开始项目”,则该选项仅与部分讨论相关PCRE Regular Expression Details

ucp

指定在解析\B,\b,\D,\d,\S,\s,\W和\w时使用Unicode字符属性。没有这个标志,只使用ISO Latin-1属性。使用Unicode属性会影响性能,但在使用超出ISO Latin-1范围的Unicode字符时语义上是正确的。

never_utf

指定禁止(* UTF)和/或(* UTF8)“模式开始项目”。该标志不能与选项结合使用unicode。如果要编译来自外部源的ISO拉丁语-1模式,则该模式很有用。

inspect(MP, Item) -> {namelist, binary()}

类型

采用编译的正则表达式和项目,并从正则表达式返回相关数据。唯一受支持的项目是namelist,返回{namelist, [binary()]}包含正则表达式中所有(唯一)命名子模式的名称的元组。例如:

1> {ok,MP} = re:compile("(?<A>A)|(?<B>B)|(?<C>C)").
{ok,{re_pattern,3,0,0,
                <<69,82,67,80,119,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,
                  255,255,...>>}}
2> re:inspect(MP,namelist).
{namelist,[<<"A">>,<<"B">>,<<"C">>]}
3> {ok,MPD} = re:compile("(?<C>A)|(?<B>B)|(?<C>C)",[dupnames]).
{ok,{re_pattern,3,0,0,
                <<69,82,67,80,119,0,0,0,0,0,8,0,1,0,0,0,255,255,255,255,
                  255,255,...>>}}
4> re:inspect(MPD,namelist).                                   
{namelist,[<<"B">>,<<"C">>]}

在第二个例子中注意,重复名称只在返回列表中出现一次,并且列表按字母顺序排列,而不管名称在正则表达式中的位置。如果{capture, all_names}被指定为选项,名称的顺序与捕获的子表达式的顺序相同run/3。因此,您可以像这样创建一个名称到值的映射run/3

1> {ok,MP} = re:compile("(?<A>A)|(?<B>B)|(?<C>C)").
{ok,{re_pattern,3,0,0,
                <<69,82,67,80,119,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,
                  255,255,...>>}}
2> {namelist, N} = re:inspect(MP,namelist).
{namelist,[<<"A">>,<<"B">>,<<"C">>]}
3> {match,L} = re:run("AA",MP,[{capture,all_names,binary}]).
{match,[<<"A">>,<<>>,<<>>]}
4> NameMap = lists:zip(N,L).
[{<<"A">>,<<"A">>},{<<"B">>,<<>>},{<<"C">>,<<>>}]

replace(Subject, RE, Replacement) -> iodata() | unicode:charlist()

类型

replace(Subject, RE, Replacement, [])一样。

replace(Subject, RE, Replacement, Options) ->

iodata() | unicode:charlist()

类型

Subject用内容替换字符串的匹配部分Replacement

run/3除了该选项capture不被允许外,允许的选项与for相同。相反{return, ReturnType},存在。默认返回类型是以iodata最小化复制的方式构造的。该iodata结果可以直接在许多I / O操作中使用。如果需要单位list(),请指定{return, list}。如果需要二进制文件,请指定{return, binary}

在函数中run/3mp()带有选项的编译unicode需要Subject是Unicode charlist()。如果编译是隐式完成的,并且unicode为此函数指定了编译选项,则正则表达式将Subject被指定为有效的Unicode charlist()

替换字符串可以包含特殊字符&,该字符在结果中插入整个匹配表达式,并且将特殊序列\N(其中N是大于0的整数),\gN或\g{N },导致子表达式编号N插入到结果。如果正则表达式不生成具有该编号的子表达式,则不插入任何内容。

要在结果中插入&或\,请在前面加上一个。请注意,Erlang已经在文字字符串中给\赋予了一个特殊的含义,所以单个\必须写为"\\"\,因此是双\ "\\\\"

例子:

re:replace("abcd","c","[&]",[{return,list}]).

施予

"ab[c]d"

re:replace("abcd","c","[\\&]",[{return,list}]).

施予

"ab[&]d"

run/3一样,编译错误会引发badarg异常。compile/2可用于获取有关错误的更多信息。

run(Subject, RE) -> {match, Captured} | nomatch

类型

run(Subject,RE,[])一样。

run(Subject, RE, Options) ->

{match, Captured} | match | nomatch | {error, ErrType}

类型

      参见[`compile / 2`](about:blank#compile_options)。        

执行正则表达式匹配,并返回match/{match, Captured}nomatch。正则表达式可以被指定为iodata()在这种情况下它被自动编译(作为compile/2)并且被执行,或者被预编译,mp()在这种情况下它直接对主题执行。

当涉及编译时,badarg如果发生编译错误,则抛出异常。调用compile/2以获取有关正则表达式中错误位置的信息。

如果正则表达式是先前编译的,则选项列表只能包含以下选项:

  • anchored
  • {capture, ValueSpec}/{capture, ValueSpec, Type}
  • global
  • {match_limit, integer() >= 0}
  • {match_limit_recursion, integer() >= 0}
  • {newline, NLSpec}
  • notbol
  • notempty
  • notempty_atstart
  • noteol
  • {offset, integer() >= 0}
  • report_errors

否则,所有对功能有效的选项compile/2也是允许的。选项允许编译和执行匹配,即,anchored{newline, NLSpec},如果与非预编译的正则表达式一起存在,则影响编译和执行。

如果正则表达式之前用选项编译unicodeSubject是一个有效的Unicode来提供charlist()的,否则任何iodata()会做。如果涉及编译并且unicode指定了选项Subject,则将这两者和正则表达式指定为有效的Unicode charlists()

{capture, ValueSpec}/{capture, ValueSpec, Type}定义成功匹配时从函数返回的内容。该capture元组可以包含一个值规范,告诉哪些捕获的子字符串将被返回,以及类型规范,告诉如何捕获的子字符串将被返回(作为索引元组,列表或二进制文件)。这些选项在下面详细描述。

如果捕获选项描述没有完成子字符串捕获({capture, none}),则该函数match在成功匹配时返回单个原子,否则返回元组{match, ValueList}。禁用捕获可以通过指定none或空列表来完成ValueSpec

选项report_errors增加了返回错误元组的可能性。元组或者表示匹配错误(match_limit或者match_limit_recursion),或者错误元组具有格式的编译错误{error, {compile, CompileErr}}。请注意,如果report_errors未指定选项,则该函数永远不会返回错误元组,但会将编译错误报告为badarg异常,并且由于超出了匹配限制而导致匹配失败nomatch

下列选项与执行有关:

anchored

限制run/3在第一个匹配位置进行匹配。如果一个模式是通过内容编译的anchored,或者是凭借其内容来锚定的,那么在匹配的时候就不能使它无法链接,因此没有unanchored选择。

global

实现全局(重复)搜索(gPerl中的标志)。每个匹配被返回作为一个单独的list()如由选项指定包含特定比赛和任何匹配子表达式(或captureCaptured返回值的部分是因此具有list()list()秒为单位指定这个选项时。

选项global与匹配空字符串的正则表达式的交互使一些用户感到惊讶。如果global指定了选项,则按照run/3与Perl相同的方式处理空匹配项:任何点的零长度匹配也会重试选项[anchored, notempty_atstart]。如果该搜索给出长度> 0的结果,则包括结果。例:

re:run("cat","(|at)",[global]).

执行下列匹配:

在偏移处0

正则表达式(|at)首先匹配字符串的初始位置cat,给出结果集[{0,0},{0,0}](第二个{0,0}是由于括号表示的子表达式)。由于比赛的长度为0,我们还没有前进到下一个位置。

在偏移处0带着[anchored, notempty_atstart]

搜索将[anchored, notempty_atstart]在同一位置重试选项,但不会给出长度较长的有趣结果,因此搜索位置会前进到下一个字符(a)。

在偏移处1

搜索结果中[{1,0},{1,0}],所以这个搜索也是重复的额外选项。

在偏移处1带着[anchored, notempty_atstart]

替代方法ab已找到,结果为{1,2},{1,2}。结果将被添加到结果列表中,并且搜索字符串中的位置将前进两个步骤。

在偏移处3

搜索再次匹配空字符串,给[{3,0},{3,0}]

在偏移处1带着[anchored, notempty_atstart]

这没有给出长度>0的结果,我们位于最后一个位置,所以全局搜索已经完成。

调用的结果是:

{match,[[{0,0},{0,0}],[{1,0},{1,0}],[{1,2},{1,2}],[{3,0},{3,0}]]}

notempty

如果指定了此选项,则空字符串不被视为有效匹配。如果存在这种模式的替代品,那么他们就会尝试。如果所有替代方案都与空字符串匹配,则整个匹配失败。

例子:

如果以下模式应用于不以“a”或“b”开头的字符串,它通常会匹配主题开头处的空字符串:

a?b?

使用选项notempty,此匹配无效,因此可以run/3进一步搜索字符串以查找“a”或“b”的出现。

notempty_atstart

就像notempty,除了不允许在主题开始处的空字符串匹配。如果模式被锚定,那么只有当模式包含\ K时才会发生这种匹配。

Perl与notemptyor 没有直接的等价关系notempty_atstart,但它确实在split()函数内以及使用修饰符时创建了空字符串模式匹配的特例/g。Perl行为可以在匹配一个空字符串之后模拟,首先在与notempty_atstartand 相同的偏移处再次尝试匹配anchored,然后如果失败,则通过推进起始偏移量(见下文)并再次尝试普通匹配。

notbol

指定主题字符串的第一个字符不是一行的开头,所以在它之前不要匹配音调元字符。没有multiline(在编译时)设置它会导致回音永远不匹配。此选项仅影响旋转元字符的行为。它不影响\A。

noteol

指定主题字符串的结尾不是一行的结尾,所以美元元字符不能与它匹配,也不能(除了在多行模式中)紧接在它之前的换行符。没有multiline(在编译时)设置它会导致美元永远不匹配。该选项仅影响美元元字符的行为。它不会影响\ Z或\ z。

report_errors

更好地控制错误处理run/3。指定时,编译错误(如果正则表达式尚未编译)和运行时错误显式返回为错误元组。

以下是可能的运行时错误:

match_limit

PCRE库设置了可以调用内部匹配函数的次数限制。在为Erlang编译的库中默认为10,000,000。如果{error, match_limit}返回,则正则表达式的执行已达到此限制。这通常被认为是a nomatch,这是发生这种情况时的默认返回值,但通过指定report_errors,由于内部呼叫太多而导致匹配失败时通知您。

match_limit_recursion

这个错误非常相似match_limit,但是当PCRE的内部匹配函数被“递归”调用的次数超过match_limit_recursion限制时,会出现这个错误,默认值也是10,000,000。请注意,只要值match_limitmatch_limit_default值保持默认值,match_limit_recursion错误就不会发生,因为match_limit错误发生在此之前(每次递归调用也是一次调用,但不是相反)。但是,通过直接在正则表达式字符串中设置限制(请参阅部分PCRE Regular Eexpression Details)或通过指定选项来更改这两个限制run/3

重要的是要理解,当限制匹配时,所谓的“递归”并不是在Erlang机器的C堆栈上或在Erlang进程堆栈上递归。编译到ErlangVM中的PCRE版本使用机器“堆”内存来存储必须在正则表达式匹配中保持递归的值。

{match_limit, integer() >= 0}

以特定于实现的方式限制匹配的执行时间。PCRE文件描述如下:

The match_limit field provides a means of preventing PCRE from using
up a vast amount of resources when running patterns that are not going
to match, but which have a very large number of possibilities in their
search trees. The classic example is a pattern that uses nested
unlimited repeats.

Internally, pcre_exec() uses a function called match(), which it calls
repeatedly (sometimes recursively). The limit set by match_limit is
imposed on the number of times this function is called during a match,
which has the effect of limiting the amount of backtracking that can
take place. For patterns that are not anchored, the count restarts
from zero for each position in the subject string.

这意味着如果使用此选项降低限制,失控的正则表达式匹配可能会更快失败。默认值10,000,000被编译到Erlang VM中。

在“长时间运行的BIF”方面,该选项决不会影响Erlang VM的执行。run/3始终以确保Erlang系统的实时属性的间隔将控制权交给Erlang进程的调度器。

{match_limit_recursion, integer() >= 0}

以特定于实现的方式限制匹配的执行时间和内存消耗,非常类似于match_limit。PCRE文件描述如下:

The match_limit_recursion field is similar to match_limit, but instead
of limiting the total number of times that match() is called, it
limits the depth of recursion. The recursion depth is a smaller number
than the total number of calls, because not all calls to match() are
recursive. This limit is of use only if it is set smaller than
match_limit.

Limiting the recursion depth limits the amount of machine stack that
can be used, or, when PCRE has been compiled to use memory on the heap
instead of the stack, the amount of heap memory that can be used.

Erlang虚拟机使用PCRE库,在发生正则表达式匹配递归时使用堆内存。这因此限制了机器堆的使用,而不是C堆栈。

指定较低的值可能导致匹配严重递归失败,而它们本应匹配:

1> re:run("aaaaaaaaaaaaaz","(a+)*z").
{match,[{0,14},{0,13}]}
2> re:run("aaaaaaaaaaaaaz","(a+)*z",[{match_limit_recursion,5}]).
nomatch
3> re:run("aaaaaaaaaaaaaz","(a+)*z",[{match_limit_recursion,5},report_errors]).
{error,match_limit_recursion}

这个选项和选项match_limit只能在极少数情况下使用。建议在篡改这些限制之前了解PCRE库内部。

{offset, integer() >= 0}

在主题字符串中指定的偏移量(位置)处开始匹配。偏移量是从零开始的,所以默认值是{offset,0}(所有主题字符串)。

{newline, NLSpec}

覆盖主题字符串中的换行符的默认定义,即Erlang中的LF(ASCII 10)。

cr

换行符由单个字符CR(ASCII 13)表示。

lf

换行符由单个字符LF(ASCII 10)表示,默认值为。

crlf

换行符由双字符CRLF(ASCII 13和ASCII 10)序列表示。

anycrlf

前三个序列中的任何一个都被识别。

any

以上任何一种换行符序列和Unicode序列VT(垂直制表符,U + 000B),FF(换页符,U + 000C),NEL(下一行,U + 0085),LS(行分隔符,U + 2028)和PS(段落分隔符,U + 2029)。

**`bsr_anycrlf`**  

具体指定\R仅匹配CR LF或CRLF序列,不匹配特定于Unicode的换行符。(重写编译选项。)

bsr_unicode

具体指定\R将匹配所有Unicode换行符(包括CRLF,等等,默认值)。(重写编译选项。)

{capture, ValueSpec}**/**{capture, ValueSpec, Type}

指定哪些捕获的子字符串以什么格式返回。默认情况下,run/3捕获子字符串的所有匹配部分和所有捕获子模式(所有模式都会自动捕获)。默认返回类型是字符串捕获部分的(从零开始的)索引,指定为{Offset,Length}对(index Type捕获)。

作为默认行为的一个例子,以下调用作为第一个也是唯一一个捕获的字符串,将主题的匹配部分(中间的“abcd”)作为索引对返回{3,4},其中字符位置是基于零的,就像偏移:

re:run("ABCabcdABC","abcd",[]).

此调用的返回值为:

{match,[{3,4}]}

另一个(也是相当常见的)案例是正则表达式匹配所有主题的地方:

re:run("ABCabcdABC",".*abcd.*",[]).

这里的返回值相应地指出了从索引0开始的所有字符串,并且它是10个字符长:

{match,[{0,10}]}

如果正则表达式包含捕获子模式,如:

re:run("ABCabcdABC",".*(abcd).*",[]).

捕获所有匹配的主题以及捕获的子字符串:

{match,[{0,10},{3,4}]}

完整的匹配模式总是给出列表中的第一个返回值,剩余的子模式按照它们在正则表达式中出现的顺序添加。

捕获元组构建如下:

ValueSpec

指定要返回哪些捕获(子)模式。ValueSpec可以是描述预定义返回值集合的原子,也可以是包含索引或要返回的特定子模式名称的列表。

以下是预定义的子模式集:

all

所有捕获的子模式包括完整的匹配字符串。这是默认设置。

all_names

正则表达式中的所有命名子模式,就像list()指定了按字母顺序排列的所有名称中的一个。所有名字的列表也可以通过检索inspect/2

first

只有第一个捕获的子模式,它始终是主题的完整匹配部分。所有显式捕获的子模式都被丢弃。

all_but_first

除第一个匹配的子模式外,即所有显式捕获的子模式,但不是主题字符串的完整匹配部分。如果正则表达式作为一个整体与主体的大部分相匹配,但是您感兴趣的部分位于明确捕获的子模式中,则这非常有用。如果返回类型是listbinary不返回的子模式,您不感兴趣是一种优化的好方法。

none

返回没有匹配的子模式,match当匹配成功而不是{match, list()}返回时,将单个atom 作为函数的返回值。指定一个空列表给出了相同的行为。

值列表是要返回的子模式的索引列表,其中索引0表示所有模式,而1表示正则表达式中的第一个显式捕获子模式,依此类推。在正则表达式中使用命名捕获的子模式(见下文)时,可以使用atom()s或string()s来指定要返回的子模式。例如,考虑正则表达式:

".*(abcd).*"

与字符串“ABCabcdABC”匹配,仅捕获“abcd”部分(第一个显式子模式):

re:run("ABCabcdABC",".*(abcd).*",[{capture,[1]}]).

该调用给出以下结果,因为第一个明确捕获的子模式是“(abcd)”,与长度为4的(从零开始的)位置3的主题匹配“abcd”

{match,[{3,4}]}

考虑相同的正则表达式,但是具有明确命名为'FOO'的子模式:

".*(?<FOO>abcd).*"

使用这个表达式,我们仍然可以使用以下调用提供子模式的索引:

re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,[1]}]).

给出和以前一样的结果。但是,当子模式被命名时,我们也可以在值列表中指定它的名称:

re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,['FOO']}]).

这将产生与前面的例子相同的结果,即:

{match,[{3,4}]}

值列表可以指定不存在于正则表达式中的索引或名称,在这种情况下,返回值因类型而异。如果类型为index{-1,0}则返回正则表达式中元组的值而不具有相应的子模式,但对于其他类型(binarylist),这些值分别是空的二进制或列表。

Type

可选择指定如何返回捕获的子字符串。如果省略,index则使用默认值。

Type可以是下列之一:

index

将捕获的子字符串返回为主题字符串中的字节索引对和主题中匹配字符串的长度(就像主题字符串在匹配时erlang:iolist_to_binary/1unicode:characters_to_binary/2在匹配之前一样)。请注意,选项会unicode导致(可能是虚拟的)UTF-8编码二进制文件中面向字节的索引。因此,字节索引元组{0,2}unicode生效时可以表示一个或两个字符。这看起来可能与直觉相反,但被认为是最有效和最实用的方法。如果需要,返回列表可能会导致更简单的代码。这种返回类型是默认的。

list

返回匹配的子字符串作为字符列表(Erlang string()的)。它选项unicode与正则表达式中的\ C序列结合使用,捕获的子模式可以包含无效UTF-8字节(\ C与字节匹配,无论字符编码如何)。在这种情况下,list捕获可能导致unicode:characters_to_list/2返回相同类型的元组,即具有标记的三元组,incomplete或者error成功转换的字符以及转换的无效UTF-8尾部作为二进制。最好的策略是避免在捕获列表时使用\ C序列。

binary

将匹配的子字符串作为二进制返回。如果使用选项unicode,这些二进制文件是UTF-8。如果\ C序列一起使用unicode,二进制文件可能是无效的UTF-8。

在一般情况下,并没有在比赛中分配一个值的子模式返回的元组{-1,0}的时候typeindex。未分配的子模式分别作为其他返回类型的空二进制或列表返回。考虑下面的正则表达式:

".*((?<FOO>abdd)|a(..d)).*"

有三个显式捕获子模式,其中左括号位置决定了结果的顺序,因此((?<FOO>abdd)|a(..d))是子模式索引1,(?<FOO>abdd)子模式索引2,(..d)子模式索引3.当与以下字符串匹配时:

"ABCabcdABC"

索引2处的子模式不匹配,因为字符串中不存在“abdd”,但完整模式匹配(由于替代方式a(..d))。因此索引2处的子模式未分配,并且默认返回值为:

{match,[{0,10},{3,4},{-1,0},{4,3}]}

设置捕获Typebinary给予:

{match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]}

这里空的binary(<<>>)表示未分配的子模式。在这种binary情况下,关于匹配的一些信息因此丢失,<<>>也可以是捕获的空字符串。

如果需要区分空匹配和不存在的子模式,请使用type indexErlang代码中的最终类型进行转换。

何时选择global是具体化的,capture规范分别影响每个匹配,因此:

re:run("cacb","c(a|b)",[global,{capture,[1],list}]).

施予

{match,[["a"],["b"]]}

有关仅影响编译步骤的选项的说明,请参阅compile/2

split(Subject, RE) -> SplitList

类型

split(Subject, RE, [])一样。

split(Subject, RE, Options) -> SplitList

类型

    See [`compile/2`](about:blank#compile_options).      

根据提供的正则表达式查找令牌,将输入拆分为部分。分割基本上是通过运行全局正则表达式匹配来完成的,并在发生匹配的地方分割初始字符串。该字符串的匹配部分从输出中删除。

和in一样run/3mp()带有选项的编译unicode需要Subject是Unicode charlist()。如果编译是隐式完成的并且unicode为此函数指定了编译选项,则正则表达式和Subject指定为有效的Unicode charlist()s。

结果以“字符串”列表的形式给出,该字符串是选项return(默认iodata)中指定的首选数据类型。

如果在正则表达式中指定了子表达式,那么在结果列表中也会返回匹配的子表达式。例如:

re:split("Erlang","[ln]",[{return,list}]).

施予

["Er","a","g"]

re:split("Erlang","([ln])",[{return,list}]).

施予

["Er","l","a","n","g"]

匹配子表达式(由正则表达式中的括号标记)的文本被插入到找到它的结果列表中。这意味着连接整个正则表达式是单个子表达式的分割结果(如最后一个示例中所示)总是会导致原始字符串。

由于在示例中最后一部分没有匹配的子表达式(“g”),所以之后没有插入任何内容。为了使字符串和与子表达式匹配的部分更加明显,可以使用选项group,该选项将字符串拆分时主题字符串的部分与匹配子表达式的部分组合在一起:

re:split("Erlang","([ln])",[{return,list},group]).

施予

[["Er","l"],["a","n"],["g"]]

这里正则表达式首先匹配“l”,导致“Er”成为结果中的第一部分。当正则表达式匹配时,(唯一)子表达式与“l”绑定,所以“l”与“Er”一起插入到组中。接下来的比赛是“n”,使得“a”成为下一个要返回的部分。由于在这种情况下子表达式绑定到子字符串“n”,因此将“n”插入到该组中。最后一组由剩余的字符串组成,因为找不到更多匹配。

默认情况下,该函数返回字符串的所有部分,包括空字符串,例如:

re:split("Erlang","[lg]",[{return,list}]).

施予

["Er","an",[]]

因为字符串末尾的“g”匹配会留下一个空白的休息符号,这也会返回。此行为不同于Perl中分割函数的默认行为,其中默认删除最后的空字符串。要获得Perl的“修剪”默认行为,请指定trim为一个选项:

re:split("Erlang","[lg]",[{return,list},trim]).

施予

["Er","an"]

“trim”选项说,“give me as many parts as possible except the empty ones”,这有时可能是有用的。你也可以指定你想要的部分,指定{parts,N }

re:split("Erlang","[lg]",[{return,list},{parts,2}]).

施予

["Er","ang"]

请注意,最后一部分是“ang”,而不是“an”,因为分割被分为两部分,并且在给出足够部分时分裂停止,这就是为什么结果不同于trim

在这个inData中,不可能有三个以上的部分,所以

re:split("Erlang","[lg]",[{return,list},{parts,4}]).

给出与默认值相同的结果,将其视为“an infinite number of parts”。

指定0为零件的数量与选项具有相同的效果trim。如果子表达式被捕获,则在结束时匹配的空子表达式也将被从结果中剥离,如果trim或者{parts,0}被指定的话。

trim行为完全对应于Perl默认值。{parts,N},其中N是正整数,与具有正数值第三参数的Perl行为完全对应。split/3当一个负整数被指定为Perl例程的第三个参数时,默认行为对应于Perl行为。

以前未说明的功能选项摘要run/3*

{return,ReturnType}

指定原始字符串的部分在结果列表中的显示方式。有效的类型:

iodata

这种变体iodata()使得数据与当前实现(通常是二进制,但不依赖于它)的复制最少。

binary

所有部分都以二进制形式返回。

list

作为字符列表返回的所有部分(“字符串”)。

**`group`**  

将字符串的部分与匹配正则表达式的子表达式的字符串的部分组合在一起。

从函数的返回值是在这种情况下list()list()秒。每个子列表以从主题字符串中挑选出的字符串开始,然后按照正则表达式中出现的顺序匹配每个子表达式。

{parts,N}

指定要将主题字符串拆分为的部分的数量。

对于特定的最大零件infinity数量以及可能的最大零件数量(缺省),零件的数量应为正整数。指定{parts,0}尽可能多的部分尽可能地忽略最后的空白部分,与指定相同trim

trim

指定结果列表末尾的空白部分将被忽略。与指定相同{parts,0}。这对应split于Perl中内置函数的默认行为。

类Perl正则表达式语法

以下部分包含本模块使用的正则表达式的参考资料。该信息基于PCRE文档,其中该模块的行为与PCRE库的行为不同。

PCRE正则表达式详细信息

以下各节详细介绍PCRE支持的正则表达式的语法和语义。Perl的正则表达式在它自己的文档中有描述,一般的正则表达式在很多书中都有介绍,其中一些有很多例子。Jeffrey Friedl的O'Reilly出版的“掌握正则表达式”涵盖了非常详细的正则表达式。PCRE正则表达式的这种描述是作为参考材料的。

参考资料分为以下几部分:

  • Special Start-of-Pattern Items
  • Characters and Metacharacters
  • Backslash
  • Circumflex and Dollar
  • Full Stop (Period, Dot) and \N
  • Matching a Single Data Unit
  • Square Brackets and Character Classes
  • Posix Character Classes
  • Vertical Bar
  • Internal Option Setting
  • Subpatterns
  • Duplicate Subpattern Numbers
  • Named Subpatterns
  • Repetition
  • Atomic Grouping and Possessive Quantifiers
  • Back References
  • Assertions
  • Conditional Subpatterns
  • Comments
  • Recursive Patterns
  • Subpatterns as Subroutines
  • Oniguruma Subroutine Syntax
  • Backtracking Control

特殊模式开始项目

一些可以传递给的选项compile/2也可以在模式开始时由特殊项目设置。这些不是Perl兼容的,但提供这些选项是为了让模式编写人员无法更改处理模式的程序而访问这些选项。任何数量的这些项目都可以出现,但它们必须全部在模式字符串的开始处在一起,并且字母必须是大写字母。

UTF支撑

Unicode支持基本上是基于UTF-8的。要使用Unicode字符,您可以调用compile/2run/3使用选项unicode,或者模式必须以以下特殊序列之一开头:

(*UTF8)
(*UTF)

两个选项都具有相同的效果,输入字符串被解释为UTF-8。请注意,根据这些说明,列表自动转换为UTF-8不是由re函数执行的。因此,不推荐使用这些序列。改为unicode运行时添加选项compile/2

一些允许其用户提供模式的应用程序出于安全原因可能希望将其限制为非UTF数据。如果never_utf在编译时设置选项,则不允许(* UTF)等,并且它们的外观会导致错误。

Unicode属性支持

下面是另一个特殊的序列,可以出现在模式的开头:

(*UCP)

这与设置选项具有相同的效果ucp:它使\ d和\ w这样的序列使用Unicode属性来确定字符类型,而不是仅通过查找表识别代码<256的字符。

禁用启动优化

如果一个模式开始(*NO_START_OPT),它与no_start_optimize编译时的设置选项具有相同的效果。

纽兰公约

PCRE支持五种用于指示字符串换行符的约定:单个CR(回车)字符,单个LF(换行符)字符,两个字符的序列CRLF,前面三个中的任何一个,以及任何Unicode换行符序列。

还可以通过使用以下五个序列之一启动模式字符串来指定换行符约定:

(* CR)回车符(* LF)换行符(* CRLF) >回车符后跟换行符(* ANYCRLF)以上三者中的任何一个(* ANY)所有Unicode换行符序列

这些覆盖默认值和指定的选项compile/2。例如,以下模式将约定更改为CR:

(*CR)a.b

这种模式匹配a\nb,因为LF不再是换行符。如果存在多于一个,则使用最后一个。

换行符约定会影响旋转和美元断言的真实位置。它还会影响dotall未设置时的点元字符的解释以及\N的行为。但是,它不影响\R转义序列匹配的内容。默认情况下,这是用于Perl兼容性的任何Unicode换行符序列。但是,这可以改变;请参阅部分中\R的说明Newline Sequences。\R设置的更改可以与新行约定的更改结合使用。

设置匹配和递归限制

调用者run/3可以对调用内部match()函数的次数和递归调用的最大深度设置限制。提供这些设施是为了捕捉由具有巨大匹配树的模式引起的失控匹配(典型的例子是具有嵌套无限重复的模式)并避免由于递归太多而耗尽系统堆栈。当达到其中一个限制时,pcre_exec()返回错误。限制也可以通过以下形式的模式开始处的项目来设置:

(*LIMIT_MATCH=d)
(*LIMIT_RECURSION=d)

这里d是任意数字的小数位数。但是,该设置的值必须小于调用者设置的值run/3才能起作用。也就是说,模式编写器可以降低程序员设置的限制,但不会提高它。如果这些限制之一有多个设置,则使用较低的值。

在Erlang虚拟机中,这两个限制的默认值都是10,000,000。请注意,递归限制不会影响虚拟机的堆栈深度,因为Erlang的PCRE以这样的方式编译,即匹配函数从不在C堆栈上递归。

请注意,LIMIT_MATCHLIMIT_RECURSION只能减少由主叫方设置的限制值,不会增加他们。

字符和元字符

正则表达式是从左到右与主题字符串匹配的模式。大多数角色代表自己的模式,并与主题中的相应角色相匹配。作为一个简单的例子,下面的模式匹配与自身相同的主题字符串的一部分:

The quick brown fox

当指定了caseless大小写匹配(选项)时,字母与大小写无关。

正则表达式的力量来自于在模式中包含替代和重复的能力。这些都是使用元字符编码的模式,它们并不代表它们自己,而是以某种特殊的方式进行解释。

存在两组元字符:那些在方括号内除模式内的任何地方识别的元字符,以及在方括号内识别的元字符。在方括号之外,元字符如下所示:

**具有多种用途的常规转义字符 ^ 断言字符串开头(或多行模式下的行) $ 断言字符串结尾(或行,多行模式)匹配除换行符之外的任何字符(默认情况下) [ 开始字符类定义 | 替代分支的开始开始子模式结束子模式扩展(也是0或1量词,还有量词最小化器 * 0或更多量词 + 1或更多量词,也是“所有格量词”)的含义 {**开始最小/最大量词

方括号内的部分模式称为“字符类”。以下是字符类中唯一的元字符:

**一般转义字符 ^ 否定类,但只限于第一个字符 - 表示字符范围第六个字符类(仅当后面跟有Posix语法时) **终止字符类

下面的部分描述了每个元字符的使用。

反斜杠

反斜杠字符有很多用途。首先,如果后面跟着一个不是数字或字母的字符,它会带走角色可以拥有的任何特殊含义。将反斜杠用作转义字符既适用于内部字符类,也适用于外部字符类。

例如,如果你想匹配*字符,你可以在模式中编写\ *。如果以下字符将被解释为元字符,则此转义操作适用,因此在带有反斜杠的非字母数字前面指定它代表自己始终是安全的。特别是,如果你想匹配一个反斜杠,write\。

unicode模式下,只有ASCII数字和字母在反斜杠后有特殊含义。所有其他字符(特别是代码点大于127的字符)都被视为文字。

如果使用option编译模式extended,则会忽略模式中的空格(字符类中除外)以及字符类和下一个换行符之外的字符之间的字符。可以使用转义反斜杠来包含空格或#字符作为模式的一部分。

要从一系列字符中删除特殊含义,请将它们放在\ Q和\ E之间。这与Perl的不同之处在于,$和@在PCRE中作为\ Q ... \ E序列中的文字处理,而$和@在Perl中引起可变插值。注意以下例子:

Pattern            PCRE matches   Perl matches

\Qabc$xyz\E        abc$xyz        abc followed by the contents of $xyz
\Qabc\$xyz\E       abc\$xyz       abc\$xyz
\Qabc\E\$\Qxyz\E   abc$xyz        abc$xyz

\ Q ... \ E序列在字符类内部和外部均被识别。\ Q之前未被隔离的\ E被忽略。如果\ Q在模式后面没有跟随\ E,字面解释会继续到模式的末尾(也就是\ E在末尾)。如果孤立的\ Q在一个字符类中,这会导致错误,因为字符类没有终止。

非印刷字符

反斜杠的第二次使用提供了以可见方式编码图案中的非打印字符的方式。对于非打印字符的外观没有限制,除了终止模式的二进制零之外。当通过文本编辑准备模式时,使用以下转义序列之一比它表示的二进制字符更容易:

\ a报警,即BEL字符(十六进制07)\ cx “Control-x”,其中x是任何ASCII字符\ e Escape(十六进制1B)\ f换页符(十六进制0C)\ n换行符(十六进制0A )\ r回车符(十六进制0D)\ t制表符(十六进制09)\ 0dd具有八进制代码的字符0dd \ ddd具有八进制代码ddd的字符或具有八进制代码ddd的反向引用\ o {ddd ..}字符.. \ xhh带十六进制代码的字符hh \ x {hhh ..}带有十六进制代码hhh的字符..

请注意,\ 0dd始终是八进制代码,而\ 8和\ 9是文字字符“8”和“9”。

\ cx对ASCII字符的精确影响如下所示:如果x是小写字母,它将转换为大写字母。然后字符的位6(十六进制40)被反转。因此\ cA到\ cZ变成十六进制01到十六进制1A(A是41,Z是5A),但是\ c {变成十六进制3B({是7B)和\ c; 变成十六进制7B(;是3B)。如果\ c后面的数据项(字节或16位值)的值大于127,则会发生编译时错误。这会锁定所有模式下的非ASCII字符。

c工具是为ASCII字符而设计的,但是扩展到Unicode之后,它就比以前更没用了。

在\ 0之后,最多读取两个八进制数字。如果少于两位数字,则只使用那些存在的数字。因此,序列\ 0 \ x \ 015指定了两个二进制零后跟一个CR字符(代码值13)。如果后面的模式字符本身是一个八进制数字,请确保在初始零后提供两位数字。

转义符\ o后面必须紧跟一系列的八进制数字,用大括号括起来。如果不是这种情况,则会发生错误。这个转义是Perl最近的补充; 它提供了将字符代码点指定为大于0777的八进制数字的方法,它还允许明确指定八进制数和后向引用。

为了更清晰明确,最好避免跟随\大于零的数字。请使用\ o {}或\ x {}指定字符编号,\ g {}指定反向引用。以下段落描述了旧的,模棱两可的语法。

处理一个反斜杠后跟一个0以外的数字很复杂,并且Perl在最近的版本中已经改变,导致PCRE也改变。在字符类外,PCRE将该数字和任何后续数字读取为十进制数字。如果数字<8,或者表达式中至少有许多先前捕获了左括号,则将整个序列作为反参考。稍后在讨论带圆括号的子模式之后提供了如何工作的描述。

在一个字符类中,或者如果\之后的十进制数大于7并且没有那么多捕获子模式,PCRE将字符字符“8”和“9”处理为\ 8和\ 9,否则重新读取到反斜杠后面的三个八进制数字,并使用它们生成数据字符。任何后续数字都代表它们自己。例如:

\ 040编写ASCII空间的另一种方式\ 40同样,只要有<40个以前的捕获子模式\ 7总是一个后退引用\ 11可以是后退引用或另一种写入制表符的方式\ 011总是一个制表符\ 0113后面带有字符“3”的选项卡\ 113可以是反向参考,否则带八进制代码的字符为113 \ 377可以是反向参考,否则为值255(十进制)\ 81可以是反向参考或两个字符“8 “和”1“

请注意,使用此语法指定的八进制值> = 100不能由前导零引入,因为不会有超过三个八进制数字被读取。

默认情况下,在\ x之后没有跟随{,从零到两个十六进制数字被读取(字母可以是大写或小写)。\ x {和}之间可能会出现任意数量的十六进制数字。如果\ x {和}之间出现十六进制数字以外的字符,或者如果没有终止},则会发生错误。

值小于256的字符可以由\ x的两种语法中的任何一种来定义。他们处理的方式没有区别。例如,\ xdc与\ x {dc}完全相同。

字符值约束

使用八进制或十六进制数字指定的字符仅限于某些值,如下所示:

8位非UTF模式

<0x100

8位UTF-8模式

<0x10ffff和有效的编码点

无效的Unicode代码点范围是0xd800到0xdfff(即所谓的“代理”代码点)和0xffef。

字符类中的转义序列

定义单个字符值的所有序列都可以在字符类内部和外部使用。此外,在字符类中,\b被解释为后退字符%28十六进制08%29。

字符类中不允许使用n。B、\R和\X在字符类中并不特殊。与其他未识别的转义序列一样,它们被视为字面字符“B”、“R”和“X”。在字符类之外,这些序列具有不同的含义。

不支持逃逸序列

在Perl中,序列\l、\L、\u和\u由其字符串处理程序识别,用于修改以下字符的情况。PCRE不支持这些转义序列。

绝对和相对反向引用

序列\g后面跟着一个无符号或负数,可选地括在大括号中,是绝对或相对的反向引用。可以将命名的回退引用编码为\g{name}。后面的引用将在后面讨论括号大小的子模式之后进行讨论。

绝对和相对子程序调用

为了与Oniguruma兼容,非Perl语法\ g后跟一个用尖括号或单引号括起来的名称或数字,是将子模式引用为“子例程”的替代语法。细节将在稍后讨论。请注意,\ g {...}(Perl语法)和\ g <...>(Oniguruma语法)不是同义词。前者是后向参照,后者是子程序调用。

属字符类型

反斜杠的另一种用法是指定泛型字符类型:

\ d任何十进制数字\ D任何非十进制数字的字符\ h任何水平空白字符\ H任何非水平空白字符的字符\ s任何空格字符\ S任何非空白字符的字符\ v任何垂直空白字符\ V任何不是垂直空白字符的字符\ w任何“字”字符\ W任何“非字”字符

还有单个序列\N,它与非换行符匹配。这与“.”是一样的。元字符dotall未设置时。Perl也使用\N来按名称匹配字符,但PCRE不支持这一点。

每对小写和大写转义序列将整个字符集分割成两个不相交的集合。任何给定的字符都与每对中的一个匹配,并且只匹配一个。序列可以出现在字符类内部和外部。它们各自匹配适当类型的一个字符。如果当前匹配点位于主题字符串的末尾,则全部失败,因为没有匹配的字符。

为了与Perl兼容,\s没有用来匹配VT字符(代码11),这使得它与POSIX“空间”类不同。但是,Perl在版本5.18中添加了VT,而PCRE在8.34版中也是如此。现在默认的\ s字符是HT(9),LF(10),VT(11),FF(12),CR(13)和空格(32),它们在“C”语言环境中定义为空白。如果发生特定于语言环境的匹配,此列表可能会有所不同。例如,在某些语言环境中,“不分隔空格”字符(\xA0)被识别为空格,而在另一些语言中,VT字符不识别。

“word”字符是下划线或任何字母或数字。默认情况下,字母和数字的定义由PCRE低值字符表控制,在Erlang的情况下(无选项unicode)是ISO Latin-1字符集。

默认情况下,在unicode模式下,值大于255的字符,即ISO Latin-1字符集外的所有字符都不匹配\d,\s或\w,并且始终匹配\D,\S和\W 。这些序列在UTF支持可用之前保留其原有含义,主要是出于效率原因。但是,如果ucp设置了选项,则会更改该行为,以便使用Unicode属性确定字符类型,如下所示:

\d \p {Nd}匹配任何字符(十进制数字)\s \p {Z}或\h或\v \w的任何字符匹配\p {L}或\p {N}加上下划线

大写转义符与反转字符集匹配。请注意,\d仅匹配十进制数字,而\w匹配任何Unicode数字,任何Unicode字母和下划线。还要注意,ucp影响\b和\B,因为它们是以\w和\W来定义的。匹配这些序列在ucp设置时明显较慢。

序列\h,\H,\v和\V是在版本5.10中添加到Perl中的功能。与其他序列(默认情况下仅匹配ASCII字符)相比,这些序列总是与特定的高值代码点相匹配,无论是否ucp设置。

以下是水平空格字符:

U + 009水平制表符U + 0020空间U + 00A0不间断空间U + 1680 Ogham空格标记U + 180E蒙古语元音分隔符U + 2000 En四U + 2001 Em四U + 2002 En空间U + 2003 Em空间U + 2004三次元空间U + 2005四次元空间U + 2006六次元空间U + 2007图形空间U + 2008标点符号空间U + 2009薄空间U + 200A发空间U + 202F不间断空间U + 205F中等数学空间U + 3000表意空间

以下是垂直空格字符:

U + 000A换行符(LF)U + 000B垂直制表符(VT)U + 000C换页符(FF)U + 000D回车符(CR)U + 0085下一行(NEL)U + 2028行分隔符U + 2029段落分隔符

在8位非UTF-8模式下,只有代码点<256的字符才是相关的。

Newline序列

在字符类外部,默认情况下,转义序列\R匹配任何Unicode换行符序列。在非UTF-8模式下,\R等同于以下内容:

(?>\r\n|\n|\x0b|\f|\r|\x85)

这是“atomic group”的一个例子,详情如下。

这个特定的组匹配两个字符的序列CR,其后跟LF或者单个字符LF(换行,U+000A),VT(垂直制表符,U+000B),FF(换页,U+000C) ,CR(回车,U+000D)或NEL(下一行,U+0085)。双字符序列被视为不能拆分的单个单元。

在Unicode模式下,添加两个以上字符,其代码点大于255:LS(行分隔符,U+2028)和PS(段落分隔符U+2029)。这些字符被识别时不需要Unicode字符属性支持。

bsr_anycrlf通过在编译时或模式匹配时设置选项,可以将R限制为仅匹配CR,LF或CRLF(而不是完整的Unicode行结尾集)。(BSR是“反斜杠R”的缩写)。当PCRE构建时,这可以作为默认值; 如果是这样,可以通过选项请求其他行为bsr_unicode。这些设置也可以通过以下列序列之一开始模式字符串来指定:

(* BSR_ANYCRLF)仅限 CR,LF或CRLF (* BSR_UNICODE)任何Unicode换行符序列

它们会覆盖指定给编译函数的缺省值和选项,但它们本身可以被指定给匹配函数的选项覆盖。请注意,这些与Perl不兼容的特殊设置只能在模式开始时识别,并且必须使用大写。如果存在多于一个,则使用最后一个。它们可以与换行符的改变结合使用; 例如,模式可以从以下开始:

(*ANY)(*BSR_ANYCRLF)

它们也可以与(* UTF8),(* UTF)或(* UCP)特殊序列组合。在字符类中,\R被视为无法识别的转义序列,因此默认情况下匹配字母“R”。

Unicode字符属性

可以使用另外三个匹配具有特定属性的字符的转义序列。在8位非UTF-8模式下,这些序列仅限于测试代码点<256的字符,但它们在此模式下工作。以下是额外的转义序列:

\p {xx}属性为xx \P {xx}的字符不带属性的字符xx \X Unicode扩展字形群集

上面xx表示的属性名称仅限于Unicode脚本名称,一般类别属性“Any”,它匹配任何字符(包括换行符)以及一些特殊的PCRE属性(将在下一节中介绍)。其他Perl属性(如“InMusicalSymbols”)目前不受PCRE支持。请注意,\P {Any}不匹配任何字符,并始终导致匹配失败。

Unicode字符集被定义为属于某些脚本。来自这些集合之一的字符可以使用脚本名称进行匹配,例如:

\p{Greek} \P{Han}

那些不属于已识别脚本的部分被归类为“Common”。以下是脚本的当前列表:

  • Arabic
  • Armenian
  • Avestan
  • Balinese
  • Bamum
  • Bassa_Vah
  • Batak
  • Bengali
  • Bopomofo
  • Braille
  • Buginese
  • Buhid
  • Canadian_Aboriginal
  • Carian
  • Caucasian_Albanian
  • Chakma
  • Cham
  • Cherokee
  • Common
  • Coptic
  • Cuneiform
  • Cypriot
  • Cyrillic
  • Deseret
  • Devanagari
  • Duployan
  • Egyptian_Hieroglyphs
  • Elbasan
  • Ethiopic
  • Georgian
  • Glagolitic
  • Gothic
  • Grantha
  • Greek
  • Gujarati
  • Gurmukhi
  • Han
  • Hangul
  • Hanunoo
  • Hebrew
  • Hiragana
  • Imperial_Aramaic
  • Inherited
  • Inscriptional_Pahlavi
  • Inscriptional_Parthian
  • Javanese
  • Kaithi
  • Kannada
  • Katakana
  • Kayah_Li
  • Kharoshthi
  • Khmer
  • Khojki
  • Khudawadi
  • Lao
  • Latin
  • Lepcha
  • Limbu
  • Linear_A
  • Linear_B
  • Lisu
  • Lycian
  • Lydian
  • Mahajani
  • Malayalam
  • Mandaic
  • Manichaean
  • Meetei_Mayek
  • Mende_Kikakui
  • Mende_Kikakui
  • Meroitic_Hieroglyphs
  • Miao
  • Modi
  • Mongolian
  • Mro
  • Myanmar
  • Nabataean
  • New_Tai_Lue
  • Nko
  • Ogham
  • Ol_Chiki
  • Old_Italic
  • Old_North_Arabian
  • Old_Permic
  • Old_Persian
  • Oriya
  • Old_South_Arabian
  • Old_Turkic
  • Osmanya
  • Pahawh_Hmong
  • Palmyrene
  • Pau_Cin_Hau
  • Phags_Pa
  • Phoenician
  • Psalter_Pahlavi
  • Rejang
  • Runic
  • Samaritan
  • Saurashtra
  • Sharada
  • Shavian
  • Siddham
  • Sinhala
  • Sora_Sompeng
  • Sundanese
  • Syloti_Nagri
  • Syriac
  • Tagalog
  • Tagbanwa
  • Tai_Le
  • Tai_Tham
  • Tai_Viet
  • Takri
  • Tamil
  • Telugu
  • Thaana
  • Thai
  • Tibetan
  • Tifinagh
  • Tirhuta
  • Ugaritic
  • Vai
  • Warang_Citi
  • Yi

每个字符只有一个Unicode常规类别属性,由两个字母的首字母缩写词指定。为了与Perl兼容,可以通过在左大括号和属性名称之间加入一个回音来指定否定。例如,\p {^ Lu}与\P{Lu}相同。

如果\p或\P只指定了一个字母,则它包含以该字母开头的所有常规类别属性。在这种情况下,如果没有否定,转义序列中的大括号是可选的。以下两个例子具有相同的效果:

\p{L}
\pL

支持以下通用类属性代码:

COtherCcControlCfFormatCnUnassignedCoPrivate useCsSurrogateLLetterLlLowercase letterLmModifier letterLoOther letterLtTitle case letterLuUppercase letterMMarkMcSpacing markMeEnclosing markMnNon-spacing markNNumberNdDecimal numberNlLetter numberNoOther numberPPunctuationPcConnector punctuationPdDash punctuationPeClose punctuationPfFinal punctuationPiInitial punctuationPoOther punctuationPsOpen punctuationSSymbolScCurrency symbolSkModifier symbolSmMathematical symbolSoOther symbolZSeparatorZlLine separatorZpParagraph separatorZsSpace separator

L&的特殊属性也受到支持。它匹配具有Lu,Ll或Lt属性的字符,即未被分类为修饰符或“其他”的字母。

Cs(代理)属性仅适用于U+D800到U+DFFF范围内的字符。这些字符在Unicode字符串中无效,因此无法通过PCRE进行测试。Perl不支持Cs属性。

由Perl支持的属性名称的长同义词(例如\p{Letter})不受PCRE支持。不允许在“是”的前面添加任何这些属性的前缀。

Unicode表中没有字符具有Cn(未分配)属性。该属性被假定为不在Unicode表中的任何代码点。

指定无外壳匹配不会影响这些转义序列。例如,\p{Lu}总是只匹配大写字母。这与当前版本的Perl的行为不同。

由Unicode属性匹配字符并不快,因为PCRE必须执行多级表查找来查找字符属性。这就是为什么像\d和\w这样的传统转义序列默认情况下不使用PCRE中的Unicode属性的原因。但是,您可以通过设置选项ucp或通过(* UCP)启动模式来完成此操作。

扩展的字形集群

\X转义匹配形成“扩展字形群集”的任意数量的Unicode字符,并将该序列视为原子组(见下文)。直到并包括版本8.31,PCRE匹配了更早的,更简单的定义,相当于(?>\PM\pM*)。也就是说,它匹配了一个没有“mark”属性的字符,后跟零个或多个带有“mark”属性的字符。带有“mark”属性的字符通常是影响前一个字符的非间距重音。

这个简单的定义在Unicode中被扩展为包含更复杂的复合字符,方法是给每个字符一个字形破坏属性,并创建使用这些属性定义扩展字形集群边界的规则。在晚于8.31的PCRE版本中,\X匹配这些集群中的一个。

\X总是匹配至少一个字符。然后根据以下规则决定是否添加更多字符来结束集群:

  • 在主题字符串的末尾结束。
  • 不要在CR和LF之间结束;否则在任何控制字符后结束。
  • 不要打破Hangul(韩文)音节序列。韩文字符有五种类型:L,V,T,LV和LVT。一个L字符可以后跟一个L,V,LV或LVT字符。一个LV或V字符可以跟一个V或T字符。一个LVT或T字符只能跟一个T字符。
  • 在扩展字符或间距标记之前不要结束。带有“extend”属性的字符总是具有“extend”字形断开属性。
  • 不要在前面的字符之后结束。
  • 否则,结束群集。

PCRE附加性能

除了前面描述的标准Unicode属性之外,PCRE还支持另外四种可以将传统转义序列(如\w和\s)转换为使用Unicode属性的可能性。当ucp选项通过时,PCRE在内部使用这些非标准的非Perl属性。但是,它们也可以明确使用。属性如下:

Xan

任何字母数字字符。匹配具有L(字母)或N(数字)属性的字符。

XPS

任何Posix空间字符。匹配字符选项卡,换行符,垂直制表符,换页符,回车符和具有Z(分隔符)属性的任何其他字符。

XSP

任何Perl空间字符。与Xps相同,但不包括垂直制表符。

XWD

任何Perl“Word”字符。匹配与Xan相同的字符,加上下划线。

Perl和POSIX空间现在是相同的。Perl在版本5.18中将VT添加到了它的空间字符集中,而PCRE在8.34版中进行了更改。

Xan匹配具有L(字母)或N(数字)属性的字符。Xps匹配字符选项卡,换行符,垂直制表符,换页符或回车符以及具有Z(分隔符)属性的任何其他字符。Xsp与Xps相同; 它用于排除垂直选项卡,以实现Perl兼容性,但Perl已更改,因此在版本8.34中遵循PCRE。Xwd匹配与Xan相同的字符,并加上下划线。

还有另一个非标准属性Xuc,它匹配任何可以用C ++和其他编程语言中的通用字符名称表示的字符。除了代理U + D800到U + DFFF外,它们是字符$,@,`(重音符号)和所有带有Unicode代码点> = U + 00A0的字符。注意大多数基本(ASCII)字符被排除。(通用字符名称的形式是\uHHHH或\UHHHHHHHH,其中H是一个十六进制数字。请注意,Xuc属性与这些序列不匹配,但它们表示的字符不匹配。)

重置匹配启动

转义序列\ K导致任何先前匹配的字符不包含在最终的匹配序列中。例如,以下模式匹配“foobar”,但报告它已匹配“bar”:

foo\Kbar

该功能类似于后向断言(如下所述)。但是,在这种情况下,真正匹配之前的主体部分不必具有固定长度,因为后向断言具有固定长度。使用\ K不会干扰捕获的子串的设置。例如,当以下模式匹配“foobar”时,第一个子字符串仍然设置为“foo”:

(foo)\Kbar

Perl文档指出,在断言中使用\K是“没有明确定义”。在PCRE中,当肯定断言发生时,\K被采取行动,但在否定断言中被忽略。请注意,如果(?= ab \K)等模式匹配,则报告的比赛开始时间可能会大于比赛结束时间。

简单断言

反斜杠的最终用途是用于某些简单的断言。断言指定了匹配中特定点必须满足的条件,而不消耗主题字符串中的任何字符。下面描述使用子模式进行更复杂的断言。以下是相反的断言:

\b匹配单词边界。\B当不在单词边界时匹配。\A匹配在主题的开始。\Z匹配主题的末尾,并在主题末尾的换行符之前匹配。\z仅在主题末尾匹配。\G匹配主题中的第一个匹配位置。

在字符类中,\b具有不同的含义;它匹配退格字符。如果其他任何断言出现在字符类中,默认情况下它会匹配相应的文字字符(例如\ B匹配字母B)。

单词边界是主题字符串中当前字符和前一个字符不匹配\w或\W(即一个匹配\w,另一个匹配\W)的位置,或者该字符的开头或结尾如果第一个或最后一个字符分别与\w匹配,则为字符串。在UTF模式下,可以通过设置选项来更改\w和\W的含义ucp。完成后,它也会影响\b和\B。PCRE和Perl没有单独的“单词开始”或“单词结束”metasequence。然而,无论如何\b通常确定它是哪一个。例如,片段\ba在单词的开头匹配“a”。

\A,\Z和\z断言与传统的曲调和美元(在下一节中描述)不同,它们只在主题字符串的开头和结尾匹配,无论设置了什么选项。因此,它们独立于多线模式。这三个断言不受选项的影响,notbolnoteol仅影响旋转元和美元元字符的行为。但是,如果参数startoffsetrun/3不为零,表明匹配是比主体的开始以外的其他点开始,\A不能比拟的。\Z和\z之间的区别在于,\Z匹配字符串末尾的换行符之前,最后匹配换行符,而\z只匹配末尾。

只有当当前匹配位置在匹配的起始点时,\G断言才为真,如参数startoffsetrun/3。它与\A的不同之处在于其值startoffset不为零。通过run/3用适当的参数多次调用,你可以模仿Perl选项/g,并且在这种实现中,\ G可以是有用的。

然而,请注意,\G作为当前匹配的开始的PCRE解释与Perl相比有微妙差异,Perl将其定义为前一次匹配的结束。在Perl中,当以前匹配的字符串为空时,这些可能会有所不同。由于PCRE一次只能匹配一个,所以无法重现此行为。

如果模式的所有选项都以\G开头,则表达式将锚定到起始匹配位置,并在编译的正则表达式中设置“anchored”标志。

Circumflex和美元

Circumflex和美元元字符是零宽度断言。也就是说,他们测试一个特定的条件为真,而不消耗主题字符串中的任何字符。

在字符类外部,在缺省匹配模式下,只有在当前匹配点位于主题字符串的起始位置时,circumflex字符才为真。如果争论startoffsetrun/3是非零,如果选项抑扬,则不能使用multiline未设置。在角色类中,回音有一个完全不同的含义(见下文)。

如果涉及一些替代方案,则Circumflex不需要成为模式的第一个字符,但是如果模式匹配该分支,它将成为每个替代方案中的第一个选项。如果所有可能的选择都以旋律开始,也就是说,如果该模式仅限于在主体开始时匹配,则被称为“锚定”模式。(还有其他构造可以使模式被锚定。)

美元字符是一个断言,只有在当前匹配点位于主题字符串的结尾处,或紧接在字符串末尾的换行符之前(默认情况下)才为真。但请注意,它与换行符不匹配。如果涉及到一些替代方案,美元不必是模式的最后一个字符,但它应该是任何分支中的最后一个分支。美元在角色等级中没有特殊含义。

通过dollar_endonly在编译时设置选项,可以更改美元的含义,以便它仅在字符串的最后匹配。这不会影响\Z断言。

如果multiline设置了选项,则会更改音符和美元字符的含义。当这种情况发生时,旋转曲线在内部换行符后面和主题字符串开始处立即匹配。它在结束字符串的换行符后不匹配。一美元在字符串中的任何换行符之前匹配,并且在最后multiline设置时匹配。当将换行符指定为两个字符的序列CRLF时,隔离的CR和LF字符不会指示换行符。

例如,模式/^ abc $/与多行模式下的主题字符串“def \nabc”(其中\n代表换行符)匹配,但不以其他方式。所以,这是在单行模式固定模式,因为所有的分支开始^不是在多行模式下锚,以及匹配抑扬有可能当争论开始偏移run/3非零。dollar_endonly如果multiline设置,选项将被忽略。

请注意,序列\A,\Z和\z可用于在两种模式下匹配主题的开始和结束。如果一个模式的所有分支都以\A开始,它总是被锚定,无论是否multiline设置。

Full Stop (Period, Dot)和\N

在字符类外部,模式中的点与主题字符串中的任何字符相匹配,但默认情况下表示行结束的字符除外。

当一行结尾被定义为单个字符时,点不匹配该字符。当使用双字符序列CRLF时,如果紧跟着LF,则点不匹配CR,否则匹配所有字符(包括隔离的CR和LF)。当任何Unicode行结尾被识别时,点不匹配CR,LF或任何其他行尾字符。

关于换行符的点行为可以改变。如果dotall设置了选项,则点无匹配地匹配任何字符。如果主题字符串中存在双字符序列CRLF,则需要两个点来匹配它。

点的处理完全独立于回音和美元的处理,唯一的关系是两者都涉及换行符。Dot在角色类中没有特殊含义。

转义序列\N的行为像一个点,除了它不受选项影响PCRE_DOTALL。也就是说,它匹配除了表示行尾之外的任何字符。Perl也使用\N来按名称匹配字符,但PCRE不支持这一点。

匹配单个数据单元

在字符类外部,转义序列\C匹配任何数据单元,无论是否设置了UTF模式。一个数据单位是一个字节。与点不同,\C总是匹配换行符。该功能在Perl中提供,以匹配UTF-8模式下的单个字节,但尚不清楚它如何有用。由于\C将字符分解为单独的数据单元,因此在UTF模式下将一个单元与\C匹配意味着剩余的字符串可能以畸形的UTF字符开头。这有未定义的结果,因为PCRE假定它处理有效的UTF字符串。

PCRE不允许\C以UTF模式出现在后向断言中(如下所述),因为这会使得不可能计算向后看的长度。

\C转义序列是最好的避免。但是,使用它避免UTF字符格式不正确的问题的一种方法是使用前视来检查下一个字符的长度,如下面的模式,它可以与UTF-8字符串一起使用(忽略空格和行休息时间):

(?| (?=[\x00-\x7f])(\C) |
    (?=[\x80-\x{7ff}])(\C)(\C) |
    (?=[\x{800}-\x{ffff}])(\C)(\C)(\C) |
    (?=[\x{10000}-\x{1fffff}])(\C)(\C)(\C)(\C))

以(?|)为开头的组(?)重置每个备选中的捕获括号(参见章节Duplicate Subpattern Numbers)。每个分支开始处的断言检查下一个UTF-8字符的值,其编码使用1,2,3或4个字节,然后字符的单个字节被适当数量的组捕获。

方括号和字符类

开放方括号引入一个字符类,由一个方括号结束。自动关闭方括号在默认情况下并不特殊。但是,如果PCRE_JAVASCRIPT_COMPAT设置了选项,则单独的关闭方括号会导致编译时错误。如果作为类的成员需要方括号,则它应该是该类中的第一个数据字符(在初始回调之后(如果存在))或用反斜杠转义。

字符类与主题中的单个字符相匹配。在UTF模式下,字符可以多于一个数据单元。匹配的字符必须位于类定义的字符集中,除非类定义中的第一个字符是旋转字符,在这种情况下,主题字符不得在该类定义的集合中。如果需要作为类的成员使用旋风,请确保它不是第一个字符,或者使用反斜杠进行转义。

例如,字符类[aeiou]匹配任何小写元音,而[^aeiou]匹配任何不是小写元音的字符。请注意,一个回音仅仅是一个方便的标记,用于通过枚举那些不在列表中的字符来指定类中的字符。以旋律开始的课程不是一个断言; 它仍会消耗主题字符串中的字符,因此如果当前指针位于字符串的末尾,则会失败。

在UTF-8模式下,值> 255(0xffff)的字符可以作为数据单元的字符串包含在类中,或者使用\x {转义机制。

当设置无格式匹配时,类中的任何字母都表示它们的大写和小写版本。例如,一个无情的[aeiou]匹配“A”和“a”,[^aeiou]无情的不匹配“A”,但是一个案例版本会。在UTF模式下,PCRE总是理解数值小于256的字符的概念,因此总是可以进行无匹配匹配。对于具有较高值的​​字符,仅当PCRE编译为Unicode属性支持时才支持case的概念。如果要在字符> =的UTF模式下使用无匹配匹配,请确保PCRE使用Unicode属性支持和UTF支持进行编译。

字符可以表示换行符匹配字符类,无论行结束序列是在使用时都从来没有在任何特殊的方式处理,并选择任何设置PCRE_DOTALLPCRE_MULTILINE使用。像^这样的类总是匹配这些字符中的一个。

减号(连字符)可用于指定字符类中的字符范围。例如,dm匹配d和m之间的任何字母,包括在内。如果班级中需要减号字符,则必须使用反斜线进行转义,或者出现在不能被解释为指示范围的位置,通常作为班级中的第一个或最后一个字符,或紧接在某个范围之后。例如,bdz匹配范围b到d中的字母,连字符或z。

文字字符“]”不能是范围的结尾字符。W-46]这样的模式被解释为一个由两个字符(“W”和“ - ”)组成的类,后跟一个字符串“46”,所以它会匹配“W46”或“-46”。但是,如果“]”用反斜杠转义,它将被解释为范围的结尾,所以W-] 46被解释为一个包含一个范围后跟另外两个字符的类。“]”的八进制或十六进制表示也可用于结束一个范围。

如果POSIX字符类(见下文)或定义单个字符的转义序列以外的转义序列出现在预期范围结尾字符的位置,则会生成错误。例如,z- \ xff是有​​效的,但是A- \ d和[A-:digit:]不是。

范围以字符值的整理顺序操作。它们也可以用于数字指定的字符,例如\000- \037。范围可以包含对当前模式有效的任何字符。

如果在设置无格式匹配时使用包含字母的范围,则无论在哪种情况下都匹配字母。例如,Wc相当于无匹配的匹配。在非UTF模式下,如果正在使用法语区域设置的字符表,\ xc8- \ xcb在两种情况下都匹配带重音的E字符。在UTF模式下,PCRE只有在编码时使用Unicode属性支持才支持大于255的字符大小写的概念。

字符转义序列\d,\D,\h,\H,\p,\P,\s,\S,\v,\V,\w和\W可以出现在字符类中,他们与班级相匹配的字符。例如,\dABCDEF与任何十六进制数字匹配。在UTF模式下,选项ucp会影响\d,\s,\w及其大写伙伴的含义,就像它们出现在字符类之外时一样(如Generic Character Types前面部分所述)。转义序列\b在字符类中具有不同的含义;它匹配退格字符。序列\B,\N,\R和\X在字符类中并不特殊。像任何其他无法识别的转义序列一样,它们被视为文字字符“B”,“N”,“R”和“X”。

对于大写字符类型,可以方便地使用circumflex来指定比匹配的小写字符类型更受限制的字符集。例如,类^\W_匹配任何字母或数字,但不是下划线,而\w包含下划线。积极的人物类被认为是“某物或某物或......”,而一个否定的类别被认为是“不是某物而不是某物而不是......”。

字符类中只识别以下元字符:

  • 反斜杠
  • 连字符(只在可以解释为指定范围的地方)
  • Circumflex(仅在开始时)
  • 打开方括号(只有当它可以被解释为引入Posix类的名称,或者用于特殊的兼容性功能时;请参阅接下来的两节)
  • 终合方架

但是,转义其他非字母数字字符不会造成任何伤害。

POSIX字符类

Perl支持字符类的Posix表示法。这使用封闭的方括号内的:和:所包含的名称。PCRE也支持这种表示法。例如,以下匹配“0”,“1”,任何字母字符或“%”:

[01[:alpha:]%]

以下是受支持的类名:

alnum字母和数字字母字母ASCII字符代码0-127 空白空间或制表仅CNTRL控制字符位数小数位数(同\ d)图形印刷字符,不包括空间小写字母打印打印字符,包括空间PUNCT印刷字符,不包括字母,数字和空格空格空格(与PCRE 8.34中的\ s相同)upper大写字母单词 “Word”字符(与\ w相同)xdigit十六进制数字

默认的“空格”字符是HT(9),LF(10),VT(11),FF(12),CR(13)和空格(32)。如果特定于语言环境的匹配正在进行,则空格字符列表可能不同; 可能会有更少或更多。对于Perl兼容性,“Space”与\ s不同,它不包括VT。但是,Perl在版本5.18处更改,而PCRE在8.34版后面。“空间”和\现在匹配相同的一组字符。

“word”这个名字是一个Perl扩展,“blank”是Perl 5.8的一个GNU扩展。另一个Perl扩展是否定,在冒号后用^字符表示。例如,以下匹配“1”,“2”或任何非数字:

[12[:^digit:]]

PCRE(和Per​​l)也识别Posix语法.ch。和= ch =其中“ch”是“整理元素”,但不支持这些元素,并且遇到错误。

默认情况下,值> 255的字符不匹配任何Posix字符类。但是,如果PCRE_UCP传递给选项pcre_compile(),则会更改某些类,以便使用Unicode字符属性。这是通过用其他序列替换某些Posix类来实现的,如下所示:

:alnum:Becomes \p{Xan}:alpha:Becomes \p{L}:blank:Becomes \h:digit:Becomes \p{Nd}:lower:Becomes \p{Ll}:space:Becomes \p{Xps}:upper:Becomes \p{Lu}:word:Becomes \p{Xwd}

否定版本,例如:^ alpha :,使用\P而不是\p。其他三个POSIX类在UCP模式下专门处理:

*图表:

这与打印时具有标记页面的字形的字符匹配。在Unicode属性中,它将所有字符与L,M,N,P,S或Cf属性相匹配,但以下情况除外:

U+061 C

Arabic Letter Mark

U+180 E

蒙古元音分隔符

U+2066-U+2069

各种“isolate"s

:print:

这与以下相同的字符匹配:graph:加上不是控件的空格字符,即带有Zs属性的字符。

:punct:

这匹配具有Unicode P(标点符号)属性的所有字符,以及代码点小于128且具有S(符号)属性的字符。

其他POSIX类不变,只匹配码点小于128的字符。

字界兼容性特性

在4.4BSD Unix中包含的符合POSIX.2的库中,丑陋的语法[:<:]和[:>:]用于匹配“词的开始”和“词的结尾”。PCRE如下处理这些项目:

[:<:]

is converted to \b(?=\w)

[:>:]

is converted to \b(?<=\w)

只有这些确切的字符序列被识别。诸如[a:<:b]之类的序列会为无法识别的POSIX类名称引发错误。这种支持与Perl不兼容。它提供来帮助从其他环境迁移,并且最好不用于任何新的模式。请注意,\b匹配单词的开始和结尾(请参阅上面的“简单断言”),并且在Perl风格的模式中,前面或后面的字符通常显示需要的内容,而不需要使用的断言以便正确给出POSIX行为。

垂直杆

垂直栏字符用于分隔替代图案。例如,以下模式匹配“gilbert”或“sullivan”:

gilbert|sullivan

可以出现任意数量的替代方案,并允许使用空替代方案(匹配空字符串)。匹配过程依次尝试每个替代方案,从左到右,并使用成功的第一个替代方案。如果选项在子模式内(在章节中定义Subpatterns),则“succeeds”意味着匹配子模式中剩余的主模式和备选模式。

内部选项设置

Perl兼容选项的设置caselessmultilinedotall,和extended可以从图案内通过之间的Perl选项字母序列改变“(?”和“)”。选项字母如下所示:

iFor caselessmFor multilinesFor dotallxFor extended

例如,(?im)设置无格式,多行匹配。这些选项也可以通过在字母前加一个连字符来解除。的组合的设置和取消如(?im-sx),它设置caselessmultiline,而重置dotall并且extended,也是允许的。如果在连字符之前和之后出现一个字母,则该选项未设置。

PCRE特定的选项dupnamesungreedyextra可以分别使用字符J,U和X以与Perl兼容选项相同的方式进行更改。

当其中一个选项更改发生在顶层(即不在子模式的括号内)时,更改将应用​​于随后的模式的其余部分。

子模式中的选项更改(请参见部分Subpatterns)仅影响其后的子模式的那一部分。所以,以下匹配abc和aBc,并且没有其他字符串(假定caseless不使用):

(a(?i)b)c

通过这种方式,可以使选项在模式的不同部分具有不同的设置。在一个备选方案中做出的任何更改都可以在同一个子模式内的后续分支中进行。例如:

(a(?i)b|c)

匹配“ab”,“aB”,“c”和“C”,但当匹配“C”时,在选项设置之前放弃第一个分支。这是因为选项设置的影响发生在编译时。否则会有一些奇怪的行为。

当调用编译或匹配函数时,应用程序可以设置其他PCRE特定的选项。有时模式可以包含特殊的前导序列,例如(* CRLF),以覆盖应用程序设置的内容或默认的内容。详情在Newline Sequences前面的部分提供。

(* UTF8)和(* UCP)前导序列可用于设置UTF和Unicode属性模式。它们分别相当于设置选项unicodeucp。(* UTF)序列是可以与任何库一起使用的通用版本。但是,应用程序可以设置选项never_utf,从而锁定(* UTF)序列的使用。

子模式

子模式由圆括号(圆括号)分隔,可以嵌套。将模式的一部分转换为子模式会做两件事:

1.

它本地化了一套替代方案。例如,以下模式匹配"cataract", "caterpillar", or "cat":

cat(aract|erpillar|)

没有括号,它会匹配“cataract”,“erpillar”或空字符串。

2.

它将子模式设置为捕获子模式。也就是说,当完整模式匹配时,与子模式相匹配的主题字符串部分将通过返回值传递给调用者run/3

开头括号从左到右(从1开始)计数以获取拍摄子模式的数字。例如,如果字符串“the red king”与下列模式相匹配,则捕获的子串是“red king”,“red”和“king”,分别编号为1,2和3:

the ((red|white) (king|queen))

平括号完成两个功能并不总是有帮助的。通常一个分组子模式不需要捕获要求。如果左括号后面跟着问号和冒号,则子模式不执行任何捕获,并且在计算任何后续捕获子模式的数量时不计算。例如,如果字符串“the white queen”与以下模式相匹配,则捕获的子串是“white queen”和“queen”,并且编号为1和2:

the ((?:red|white) (king|queen))

捕获子模式的最大数量是65535。

作为方便的简写,如果在非捕获子模式开始时需要任何选项设置,选项字母可以出现在“?”之间 和“:”。因此,以下两种模式匹配相同的一组字符串:

(?i:saturday|sunday)
(?:(?i)saturday|sunday)

由于可选分支从左到右进行尝试,并且直到达到子模式结束才重置选项,因此一个分支中的选项设置会影响后续分支,因此上述模式与“SUNDAY”和“Saturday”匹配。

重复子模式数

Perl 5.10引入了一个功能,其中子模式中的每个备选使用相同的数字来捕获括号。这样的子模式开始于(?|并且本身是非捕获子模式。例如,请考虑以下模式:

(?|(Sat)ur|(Sun))day

由于这两个替代方案都属于一个(?|组,因此两组捕获括号都被编号为1。因此,当模式匹配时,您可以查看捕获的第一个子字符串,无论哪个替代方法都匹配。当您想要捕捉多个替代品中的一个但不是全部时,该构造非常有用。在(?|组内,括号的编号与往常一样,但编号在每个分支的开始处重置。子模式后面的任何捕获圆括号的数字开始于任何分支中使用的最高数字之后。以下示例来自Perl文档; 下面的数字显示捕获内容存储在哪个缓冲区中:

# before  ---------------branch-reset----------- after
/ ( a )  (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x
# 1            2         2  3        2     3     4

对编号的子模式的反向引用使用任何子模式为该编号设置的最新值。以下模式匹配“abcabc”或“defdef”:

/(?|(abc)|(def))\1/

相反,调用子编号子模式的子程序始终引用模式中具有给定编号的第一个子程序。以下模式匹配“abcabc”或“defabc”:

/(?|(abc)|(def))(?1)/

如果具有匹配的子模式的条件测试引用非唯一编号,则如果该编号的任何子模式匹配,则测试为真。

使用这种“branch reset”功能的另一种方法是使用重复命名的子模式,如下一节所述。

命名子模式

通过数字识别圆括号很简单,但很难追踪复杂正则表达式中的数字。另外,如果表达式被修改,数字可以改变。为了解决这个难题,PCRE支持子模式的命名。在版本5.10之前,这个特性并没有被添加到Perl中。Python早期有这个功能,而PCRE在4.0版本中使用Python语法引入了它。PCRE现在支持Perl和Python语法。Perl允许编号相同的子模式具有不同的名称,但PCRE不会。

在PCRE中,可以通过三种方式之一来命名子模式:(?<name>...)或者(?'name'...)像在Perl中一样,或者(?P<name>...)在Python中。从模式的其他部分捕获括号的引用,例如后向引用,递归和条件可以通过名称和编号进行。

名称最多由32个字母数字字符和下划线组成,但必须以非数字开头。命名捕获圆括号仍然分配数字以及名称,就好像名称不存在一样。capture规范run/3,如果他们出现在正则表达式中可以使用指定的值。

默认情况下,名称在模式中必须是唯一的,但是可以通过dupnames在编译时设置选项来放宽此约束。(对于具有相同编号的子模式,总是允许使用重复名称,如前一节中所述)。重复名称对于只有一个命名圆括号的实例可以匹配的模式很有用。假设你想匹配一个工作日的名字,或者是一个3个字母的缩写或者是全名,并且在这两种情况下你都想提取缩写。以下模式(忽略换行符)可以完成这项工作:

(?<DN>Mon|Fri|Sun)(?:day)?|
(?<DN>Tue)(?:sday)?|
(?<DN>Wed)(?:nesday)?|
(?<DN>Thu)(?:rsday)?|
(?<DN>Sat)(?:urday)?

有五个捕获子串,但只有一个是在比赛后设置的。(解决这个问题的另一种方法是使用“branch reset”子模式,如前一节所述)。

为了捕获名称不唯一的命名子模式run/3,如果valuescapture语句的部分中指定了名称,则返回第一个匹配事件(从主题中的从左到右计数)。该all_names捕获值以同样的方式所有的名字相匹配。

您不能使用不同的名称来区分具有相同编号的两个子模式,因为PCRE在匹配时仅使用数字。由于这个原因,如果为具有相同编号的子模式指定了不同的名称,则在编译时会给出错误。但是,即使dupnames未设置,也可以为具有相同编号的子模式指定相同的名称。

重复

重复是由量词指定的,它可以跟随下列任何一项:

  • 文字数据字符
  • 点元字符
  • \C转义序列
  • \X转义序列
  • \R转义序列
  • 与单个字符匹配的转义符,如\d或\pl
  • 字符类
  • 反向参考(请参阅下一部分)
  • 带括号的子模式(包括断言)
  • 对子模式的子程序调用(递归或其他)

一般重复量词通过在逗号分隔的大括号(大括号)中给出两个数字来指定允许匹配的最小和最大数量。数字必须小于65536,第一个必须小于或等于第二个。例如,以下匹配“zz”,“zzz”或“zzzz”:

z{2,4}

单独的右大括号不是特殊字符。如果第二个数字被省略,但逗号存在,则没有上限。如果省略了第二个数字和逗号,则量词将指定所需匹配的确切数量。因此,以下匹配至少三个连续的元音,但可以匹配更多:

[aeiou]{3,}

以下数字正好匹配八位数:

\d{8}

在不允许使用量词的位置显示一个开头的大括号,或者与量词的语法不匹配的开头大括号被视为文字字符。例如,{,6}不是一个量词,而是一个由四个字符组成的字符串。

在Unicode模式下,量词适用于字符而不是单个数据单元。因此,例如,\x {100} {2}匹配两个字符,每个字符由UTF-8字符串中的2字节序列表示。类似地,\X {3}匹配三个Unicode扩展字形群集,每个群集可以有很多数据单元(并且它们可以具有不同的长度)。

量词{0}是允许的,导致表达式的行为就好像先前的项目和量词不存在一样。这对于从模式中的其他地方引用为子例程的子模式很有用(但另请参见部分Defining Subpatterns for Use by Reference Only)。除了具有{0}量词的子模式之外的项目在编译模式中被省略。

为方便起见,三种最常用的量词具有单字符缩写:

*Equivalent to {0,}+Equivalent to {1,}?Equivalent to {0,1}

无限循环可以通过遵循一个子模式来构造,该子模式可以不匹配没有上限的量词的字符,例如:

(a?)*

早期版本的Perl和PCRE用于在编译时为这些模式提供错误。但是,由于有些情况下可能有用,现在可以接受这种模式。但是,如果任何重复的子模式都不匹配任何字符,则循环将被强制中断。

默认情况下,量词是“贪婪的”,即它们尽可能匹配(达到允许的最大次数),而不会导致剩余的模式失败。这给出了问题的典型例子是试图在C程序中匹配注释。这些出现在/ *和* /之间。在评论中,可以出现个别*和/字符。尝试通过应用模式来匹配C注释

/\*.*\*/

到字符串

/* first comment */  not comment  /* second comment */

失败,因为它匹配整个字符串,因为*项目的贪婪。

但是,如果一个量词后跟一个问号,它就不再是贪婪的了,而是匹配最小的可能次数,所以下面的模式用C注释做了正确的事情:

/\*.*?\*/

各种量词的含义并没有改变,只有首选的匹配数量。不要将问号的使用与其作为量词本身的用法相混淆。由于它有两个用途,它有时可能会翻倍,如英寸

\d??\d

它按照偏好匹配一个数字,但如果这是剩余模式匹配的唯一方式,则可匹配两个数字。

如果ungreedy设置了选项(在Perl中不可用的选项),默认情况下量词不是贪婪的,但可以通过使用问号跟随它们来使单个的贪婪成为贪婪。也就是说,它反转了默认行为。

当加括号的子模式的最小重复次数> 1或最大值有限时,编译模式需要更多内存,与最小或最大值的大小成比例。

如果模式以.*或.{0,}和option dotall(相当于Perl选项/s)开头,因此允许点匹配换行符,则模式被隐式锚定,因为无论如何针对主题中的每个字符位置串。因此,在第一次之后的任何位置重试整场比赛没有意义。PCRE通常对待这种模式,就好像它在前面是\ A。

在已知主题字符串不包含换行符的情况下,值得设置dotall以获得此优化,或者使用^来明确指示锚定。

但是,有些情况下不能使用优化。如果。*在捕获模式中其他位置的后向引用的主题的括号内,则在稍后一次成功时,开始处的匹配可能会失败。考虑一下,例如:

(.*)abc\1

如果主题是“xyz123abc123”,则匹配点是第四个字符。因此,这种模式并不是隐含的。

隐式锚定未应用的另一种情况是,前导。*在原子组内。再一次,一开始的比赛可能会失败,在稍后的比赛成功。考虑以下模式:

(?>.*?a)b

它与主题“aab”中的“ab”匹配。使用回溯控制动词(* PRUNE)和(* SKIP)也会禁用此优化。

当重复捕获子模式时,捕获的值是匹配最终迭代的子字符串。例如,之后

(tweedle[dume]{3}\s*)+

已匹配“tweedledum tweedledee”,捕获的子字符串的值是“tweedledee”。但是,如果存在嵌套的捕获子模式,则可以在之前的迭代中设置相应的捕获值。例如,之后

/(a|(b))+/

匹配“ABA”,第二个捕获子字符串的值是“b”。

原子分组和占有量词

在最大化(“greedy”)和最小化(“非ungreedy”或“lazy”)重复的情况下,通常会导致对重复项目进行重新评估,以查看是否有不同重复次数允许剩余模式匹配。有时候,防止这种情况是有用的,或者改变匹配的性质,或者当模式的作者知道没有意义进行时,使它比其他情况下更早失败。

例如,当应用于以下主题行时,请考虑模式\d+foo:

123456bar

在匹配所有六位数字后,如果匹配“foo”失败,匹配器的正常操作是再次尝试,只有五个数字匹配项目\ d +,然后是四个,依此类推,最终失败。“原子分组”(取自杰弗里弗里德尔的书中的一个术语)提供了用于指定一旦子模式匹配的方法,就不会以这种方式重新评估。

如果在前面的例子中使用了原子分组,匹配器会在第一次无法匹配“foo”时立即放弃。符号是一种特殊的括号,从(?>下面的例子开始:

(?>\d+)foo

这种括号一旦匹配就“locks up”它所包含的模式部分,并且阻止进一步进入模式的失败回溯到其中。但是,回溯到之前的项目,正常工作。

另一种描述是,如果锚定在主题字符串中的当前点,则此类型的子模式与相同的独立模式匹配的字符串匹配。

原子分组子模式不捕获子模式。简单的例子,如上面的例子,可以被认为是一个最大化的重复,它必须吞下它所能做的一切。那么,\d +和\d+?都是准备调整它们匹配的数字以使其余模式匹配,(?>\d+)只能匹配整个数字序列。

通常原子组可以包含任何复杂的子模式,并且可以嵌套。但是,如上例所示,当原子组的子模式只是单个重复项时,可以使用称为“所有格量词”的简单符号。这由量词后面的一个额外的+字符组成。使用这个符号,前面的例子可以被重写为

\d++foo

请注意,所有格量词可以用于整个组,例如:

(abc|xyz){2,3}+

拥有量词永远是贪婪的;选项的设置ungreedy被忽略。它们是简单形式的原子团体的便利标记。然而,所有格量词和等价原子组的含义没有区别,但可能存在性能差异;占有量词可能稍微快一点。

所有格量词语法是对Perl 5.8语法的扩展。杰弗里弗里德尔在他的书的第一版中提出了这个想法(和名字)。Mike McCloskey喜欢它,所以在他构建Sun Java包时实现了它,而PCRE从那里复制了它。它最终在5.10版本中找到了进入Perl的途径。

PCRE具有自动“拥有”某些简单模式构造的优化。例如,序列A+B被视为A++B,因为当B必须跟随时,没有点回溯到A:s序列中。

当一个模式在一个子模式中包含无限次重复时,它本身可以重复无限次数,使用原子组是避免一些失败的匹配需要很长时间的唯一方法。模式

(\D+|<\d+>)*[!?]

匹配无限数量的由非数字组成的子字符串,或匹配<>中的数字,然后是!要么 ?。当它匹配时,它运行得很快。但是,如果它适用于

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

报告失败之前需要很长时间。这是因为字符串可以通过多种方式在内部\D+重复和外部重复之间进行划分,并且都必须尝试。(这个例子在最后使用!?而不是单个字符,因为PCRE和Perl都有一个优化,当单个字符被使用时允许快速失败,他们记得匹配所需的最后一个字符,并且失败如果该模式被改变以便它使用原子组,如下所示,则不能破坏非数字序列,并且快速失败:

((?>\D+)|<\d+>)*[!?]

反向引用

在字符类之外,反斜杠后接数字> 0(可能还有其他数字)是对模式中较早捕获子模式(即其左侧)的反向引用,前提是有许多先前的捕获左括号。

但是,如果反斜杠后面的十进制数字小于10,则始终将其作为反参考,并且仅在整个模式中没有多少捕获左括号时才会导致错误。也就是说,被引用的圆括号不需要在数字<10的引用的左侧。当涉及重复并且右侧的子模式已经参与了该类型的“向后引用”时,较早的迭代。

由于像\50这样的序列被解释为以八进制定义的字符,所以使用此语法不可能对数字为10或更多的子模式使用数字“前向回参考”。有关反斜杠后数字处理的更多详细信息,请参见Non-Printing Characters前面的部分。使用带括号的名称时不存在这样的问题。任何子模式的反向引用都可以使用带括号的括号(见下文)。

另一种避免使用反斜杠后数字固有歧义的方法是使用\ g转义序列。这个转义后面必须跟随一个无符号数或负数,可选地用大括号括起来。以下示例是相同的:

(ring), \1
(ring), \g1
(ring), \g{1}

无符号数字指定绝对引用,而不存在旧语法中的歧义。当文字数字跟随引用时,它也很有用。负数是相对的引用。考虑以下示例:

(abc(def)ghi)\g{-1}

\g{-1}序列是对\g之前最近开始的捕获子模式的引用,即在本例中相当于\2。同样,\g{-2} 将等同于\ 1。相对引用的使用可以在长模式中有用,也可以在通过在自身内部连接包含引用的片段创建的模式中使用。

反向引用匹配与当前主题字符串中的捕获子模式匹配的任何内容,而不是匹配子模式本身的任何内容(部分Subpattern as Subroutines描述了这样做的一种方式)。所以,下面的模式匹配“sense and sensibility”和“response and responsibility”,但不符合“sense and responsibility”:

(sens|respons)e and \1ibility

如果在回参考时有效的情况下,字母的情况是相关的。例如,以下匹配“rah rah”和“RAH RAH”,但不匹配“RAH rah”,尽管原始捕获子模式无条件匹配:

((?i)rah)\s+\1

有很多不同的方式来回写对已命名子模式的引用。在.NET语法\k{name}和Perl的语法\k<name>\k'name'支持,因为是Python语法(?P=name)。Perl 5.10中统一的后向引用语法,其中\ g可以用于数字引用和命名引用,也支持。前面的例子可以通过以下方式重写:

(?<p1>(?i)rah)\s+\k<p1>
(?'p1'(?i)rah)\s+\k{p1}
(?P<p1>(?i)rah)\s+(?P=p1)
(?<p1>(?i)rah)\s+\g{p1}

由名称引用的子模式可以出现在引用之前或之后的模式中。

对同一个子模式可以有多个返回引用。如果子模式没有用于特定的匹配,则任何对它的反向引用都会失败。例如,如果它开始匹配“a”而不是“bc”,则以下模式总是失败:

(a|(bc))\2

由于模式中可能有许多捕捉括号,因此反斜杠后面的所有数字都将作为潜在后向参考号的一部分。如果模式以数字字符继续,则必须使用某个分隔符来终止反向引用。如果extended设置了选项,则可以是空格。否则,Comments可以使用空注释(请参阅部分)。

递归反向引用

在第一次使用子模式时,它引用的括号内的后向引用失败,因此,例如(a\1)永远不匹配。但是,这样的引用在重复的子模式中可能很有用。例如,以下模式匹配任意数量的“a”和“aba”,“ababbaa”等等:

(a|b\1)+

在子模式的每次迭代中,反向引用匹配与先前迭代对应的字符串。为了使其工作,模式必须是第一次迭代不需要与后向引用匹配。这可以使用交替来完成,如上例所示,或者使用最小为零的量词。

此类型的反向引用会将它们引用的组视为原子组。一旦整个组被匹配,随后的匹配失败不会导致回溯到组中。

断言

断言是对不消耗任何字符的当前匹配点之后或之前的字符的测试。前面的部分描述了编码为\b、\B、\A、\G、\Z、\z、^和$的简单断言。

更复杂的断言被编码为子模式。有两种:在主题字符串中的当前位置前面的那些,以及在它后面的那些。断言子模式以正常方式匹配,除了它不会导致当前匹配位置被更改。

断言子模式不捕获子模式。如果这样的断言包含捕获其中的子模式,则这些被计数用于在整个模式中对捕获子模式进行编号。但是,子字符串捕获仅适用于肯定的断言。(Perl有时但并非总是在负面断言中执行捕获。)

警告

如果包含一个或多个捕获子模式的肯定断言成功,但在模式中稍后匹配失败会导致对此断言的回溯,则断言中的捕获仅在未设置较高编号的捕获时才会重置。不幸的是,这是目前实施的一个根本限制,并且由于PCRE1目前处于维修状态,所以不可能改变。

为了与Perl兼容,可以重复断言子模式。然而,多次断言相同的东西是没有意义的,捕获括号的副作用有时也会有用。实际上,只有三个案件:

  • 如果量词是{0},那么在匹配过程中断言从不遵守。但是,它可以包含通过子例程机制从别处调用的内部捕获括号组。
  • 如果量词为{0,n},其中n>0,则将其视为{0,1}。在运行时,使用或不使用断言来尝试其余模式匹配,顺序取决于量词的贪婪程度。
  • 如果最小重大于0,则量化符被忽略。当匹配期间遇到断言时,断言只服从一次。

Lookahead Assertions

Lookahead Assertions以(?=用于肯定断言和(?!用于否定断言)开始。例如,以下内容匹配一个单词后跟一个分号,但不包括分号匹配:

\w+(?=;)

下面匹配任何没有跟在“bar”后面的“foo”:

foo(?!bar)

注意,看起来相似的模式(?!foo)bardoes没有发现一个事件“bar”的前面是“foo”以外的东西,它发现了任何“bar”的情况,因为当接下来的三个字符是“bar”时 assertion(?!foo)总是为真。需要实现其他效果。如果你想在模式中的某个点强制匹配失败,最简单的方法就是使用(?!),因为一个空字符串总是匹配的。所以,一个断言需要在那里不是空字符串必须总是失败,回溯控制动词(*FAIL)或(*F)是当做(?!)。

Lookbehind Assertions

Lookbehind assertions 以(?<=用于肯定断言和(?<!为否定断言。例如,以下查找“bar”前面没有出现“foo”的情况:(?<!foo)bar lookbehind断言的内容受到限制,因此它匹配的所有字符串必须具有固定长度。但是,如果有许多顶级替代品,它们并不都必须具有相同的固定长度。因此,允许以下内容:

(?<=bullock |donky)

下面的代码在编译时会导致一个错误:

(?<!dogs?|cats?)

匹配不同长度字符串的分支只允许在向后看断言。与Perl相比,这是一个扩展,它要求所有分支匹配相同长度的字符串。由于其单个顶级分支可以匹配两种不同的长度,因此不允许使用如下所示的断言:

(?<=ab(c|de))

但是,如果重写为使用两个顶级分支:

(?<=abc|abde)

有时可以使用转义序列\K(参见上文)代替lookbehind断言来绕过固定长度的限制。

lookbehind断言的实现是,对于每个替代方案,移动当前位置暂时回到固定长度,然后尝试匹配。如果在当前位置之前没有足够的字符,断言将失败。

在UTF模式下,PCRE不允许\C escape(即使在UTF模式下与单个数据单元匹配)出现在后向断言中,因为它使它不可能计算逆序的长度。 \X和\R转义符可以匹配不同数量的数据单元,也不允许使用。

“Subroutine”调用(见下文),例如(?2)或(?&X),只能在lookbehinds中使用,只要因为子模式匹配一​​个固定长度的字符串。但是,递归不受支持。

偏向量词可与lookbehind assertion一起使用,以指定主题字符串末尾的固定长度字符串的有效匹配。当应用于不匹配的长字符串时,请考虑以下简单模式:

abcd$

由于匹配从左到右继续进行,PCRE会在主题中查找每个“a”,然后查看后面的内容是否与剩余模式相匹配。如果该模式被指定为^.*abcd$,

则首先匹配整个字符串。但是,如果失败(因为没有下面的“a”),它会回溯匹配除最后一个字符以外的所有字符,然后是除最后两个字符外的所有字符,依此类推。再次搜索“a”从右到左覆盖整个字符串,所以我们没有更好。但是,如果模式被写为

^.* +(?<=abcd),那么.* +项目就不会有回溯。它只能匹配整个字符串。随后的lookbehind断言对最后四个字符进行单个测试。如果失败,比赛立即失败。对于长字符串,这种方法会对处理时间产生重大影响。

使用多重断言

可以连续发生多种断言(任何类型的断言)。例如,下面的匹配“foo”前面有三个不是“999”的数字:

(?<=\d{3})(?<!999)foo

注意每个断言在相同点独立应用主题字符串。首先检查前三个字符是否都是数字,然后检查相同的三个字符不是“999”。这种模式不匹配前面有六个字符的“foo”,其中第一个是数字,最后三个不是“999”。例如,它不符合“123abcfoo”。要做到这一点的模式如下:

(?<=\d{3}...)(?<!999)foo

这次第一个断言查看前面的六个字符,检查前三个是数字,然后第二个断言检查前三个字符不是“999”。断言可以嵌套在任何组合中。例如,以下内容与“bar”前面的“baz”匹配,即

(?<=(?<!foo)bar)baz

以下模式匹配前面有三个数字的“foo”和任何三个不是“foo”的字符,前面是“bar”,而后面没有前面加上“foo” 999“:(?<= \ d {3}(?! 999)...)foo

有条件的子模式

可能会导致匹配过程有条件地服从子模式或根据断言的结果在两个替代子模式之间进行选择,或者特定的拍摄子模式是否已经匹配。以下是两种可能的条件子模式形式:

 (?(condition)yes-pattern)
 (?(condition)yes-pattern|no-pattern)

如果条件满足,则使用yes-pattern,否则使用no​​-pattern(如果存在)。

如果子模式中存在两个以上的替代方案,则会发生编译时错误。两种选择都可以包含任何形式的嵌套子模式,包括条件子模式;

对两种选择的限制只适用于条件的等级。下面的模式片段是一个例子,其中的选择是复杂的:

(?(1) (A|B|C) | (D | (?(2)E|F) | E) )

有四种条件:到子模式,对递归的引用,称为DEFINE的伪条件和断言。

通过Number检查Used Subpattern

如果括号之间的文本由一系列数字组成,则如果该数字的捕获子模式先前已匹配,则条件为真。如果存在多个具有相同编号的捕获子模式(请参阅前面的重复子模式编号部分),如果它们中的任何一个匹配,则条件为真。另一种表示法是在数字前加上加号或减号。在这种情况下,子模式编号是相对而非绝对的。最近打开的圆括号可以用(?(-1)来引用,下一个最近用(?(-2))等等。在内部循环中,引用后面的组也是有意义的。被打开的引用可以被引用为

(?(+1),等等(这些形式中的值为0不会被使用;

它会引发编译时错误)。考虑下面的模式,其中包含不重要的空白使其更易读(假设选项扩展)并将其分成三部分以便于讨论:

( \( )?    [^()]+    (?(1) \) )

第一部分匹配可选的左括号,如果该字符存在,则将其设置为第一个捕获的子字符串;第二部分匹配一个或多个不是括号的字符;第三部分是条件子模式,用于测试第一组括号是否匹配。也就是说,如果主题以左括号开头,则条件为真,因此yes-模式将被执行并关闭括号是必需的。否则,由于无模式不存在,子模式不匹配。也就是说,该模式匹配一​​系列非括号,可选择括在圆括号中。

如果此模式嵌入较大的模式中,则可以使用相对引用:

 ...other stuff... ( \( )?    [^()]+    (?(-1) \) ) ...

这使得片段独立于较大模式中的括号。

检查使用子模式的NamePerl

使用语法(?(<name>)...)或者(?('name')...)按名称测试使用的子模式。为了与早期版本的PCRE兼容,在Perl之前有这个工具,语法(?(name)...)也被识别出来。重写前面的例子使用命名的子模式给出:

(?<OPEN> \( )?    [^()]+    (?(<OPEN>) \) )

如果此类条件中使用的名称是重复的,则该测试将应用于具有相同名称的所有子模式,并且如果其中任何一个已匹配。

检查模式递归

如果条件是字符串(R),并且没有名称为R的子模式,则在对整个模式或任何子模式进行递归调用时条件为真。如果数字或名称前面加上&符号后跟随字母R,例如:

(?(R3)...) or (?(R&name)...)

如果最近的递归进入子模式,则条件为真或名字给出。这种情况不会检查整个递归堆栈。如果此类条件中使用的名称是重复的,则测试将应用于所有具有相同名称的子模式,并且如果其中任何一个是最近的递归,则为true。

在“Top level”中,所有这些递归测试条件是错误的。递归模式的语法如下所述。

定义仅供参考使用的子模式

如果条件是字符串(DEFINE),并且没有名称为DEFINE的子模式,则条件始终为false。在这种情况下,子模式中只能有一个选择。如果控制达到该模式中的这一点,它总是被跳过。 DEFINE的思想是它可以用来定义可以从其他地方引用的“子程序”。 (子程序的使用如下所述。)例如,可以像这样写入匹配IPv4地址的模式,例如“192.168.23.245”(忽略空格和换行符):

 (?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) )
 \b (?&byte) (\.(?&byte)){3} \b

模式的第一部分是DEFINE组,其中定义了另一个名为“字节”的组。这匹配IPv4地址的个别组件(小于256的数字)。当匹配发生时,模式的这部分被跳过,因为DEFINE的行为就像一个假的条件。该模式的其余部分使用对指定组的引用来匹配IPv4地址的四个点分隔的组件,并在每个末端坚持一个字边界。

断言条件

如果条件不是上述任何格式,则必须是断言。这可能是积极或消极的前瞻或后向断言。考虑这种模式,再次包含非显着的空白区域,并在第二行包含两个替代方案:

 (?(?=[^a-z]*[a-z])
 \d{2}-[a-z]{3}-\d{2}  |  \d{2}-\d{2}-\d{2} )

该条件是一个肯定的前瞻断言,与可选的非字母序列后跟一个字母相匹配。换句话说,它测试主题中是否存在至少一个字母。如果找到一封信,则将该主题与第一个备选方案进行匹配;否则与第二个匹配。该模式匹配两种形式之一的字符串dd-aaa-dd或dd-dd-dd,其中aaa是字母,dd是数字。

注释

以PCRE处理的模式包含评论的方式有两种。在这两种情况下,注释的开始都不能在字符类中,也不能在任何其他相关字符序列的中间,例如(?:或子模式名称或编号)。构成注释的字符不起作用在模式匹配中。

序列(?#表示注释的开始直到下一个右括号为止,不允许嵌套括号,如果设置了PCRE_EXTENDED选项,则一个未转义的#字符也会引入一个注释,在这种情况下,注释会立即继续模式中的下一个换行符或字符序列,哪些字符被解释为换行符,由传递给编译函数的选项或模式开始处的特殊序列控制,如上面标题为“换行符约定”的部分所述。注意,这种注释类型的结束是模式中的文字换行序列;碰巧代表换行符的转义序列不计数。例如,当PCRE_EXTENDED被设置时,考虑这种模式,并且默认的换行符约定有效:

 abc #comment \n still comment

在遇到#字符时,pcre_compile()跳过,寻找模式中的换行符。序列\ n在这个阶段仍然是文字,因此它不会终止注释。只有代码值为0x0a(默认换行符)的实际字符才会这样做。

递归模式

考虑在括号中匹配字符串的问题,允许无限嵌套圆括号。如果没有使用递归,可以做的最好的方法是使用匹配某种固定深度嵌套的模式。无法处理任意的嵌套深度。

一段时间以来,Perl提供了一个允许正则表达式递归的工具(等等)。它通过在运行时在表达式中插入Perl代码来实现这一点,代码可以引用表达式本身。使用代码插值解决圆括号问题的Perl模式可以像这样创建:

 $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x;

(?p{...})项在运行时插入Perl代码,在这种情况下递归引用它出现的模式。

显然,PCRE不支持Perl代码的插值。相反,它支持用于递归整个模式的特殊语法,也支持单个子模式递归。在PCRE和Python中引入之后,这种递归随后在5.10版中引入到Perl中。

一个由(?后跟一个大于零的数字和一个右括号组成的特殊项目是给定数字的子模式的递归子例程调用,只要它发生在该子模式内部(如果不是,则它是非递归的子例程调用,这在下一节中介绍。)特殊项目(?R)或(?0)是整个正则表达式的递归调用。

这个PCRE模式解决了嵌套括号问题(假设PCRE_EXTENDED选项设置为忽略空白):

 \( ( [^()]++ | (?R) )* \)

首先它匹配左括号。然后它匹配任意数量的子字符串,它们可以是非括号的序列,也可以是模式本身的递归匹配(即正确加括号的子字符串)。最后有一个右括号。请注意使用占有量词来避免回溯到非括号的序列中。

如果这是更大模式的一部分,那么您不想递归整个模式,相反,您可以使用这个:

  ( \( ( [^()]++ | (?1) )* \) )

我们把这个模式放在括号里,并且使递归引用它们而不是整个模式。

在更大的模式中,跟踪括号数可能会很棘手。这通过使用相对引用变得更容易。除了上面的模式中的(?1),您可以编写(?-2)来引用递归之前的第二个最近打开的括号。换句话说,负数表示从所遇到的点向左捕捉括号。

也可以通过编写参考(如(?+2))来引用随后打开的括号。但是,这些不能递归,因为引用不在引用的括号内。它们总是非递归子程序调用,如下一节所述。

另一种方法是使用带括号的括号。 Perl的语法是(?&name); PCRE的早期语法(?P>name)也被支持。我们可以重写上面的例子,如下所示:

(?<pn> \( ( [^()]++ | (?&pn) )* \) )

如果有多个具有相同名称的子模式,则使用最早的一个子模式。

我们一直在研究的这个特定的示例模式包含嵌套的无限重复,因此当将模式应用于不匹配的字符串时,使用所有格量词匹配非括号字符串非常重要。例如,这种模式适用于

 (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()

它会很快产生“不匹配”。但是,如果不使用所有格量词,则匹配运行的时间确实很长,因为有多种不同的方式可以分割主题,并且在报告故障之前都必须进行测试。

在比赛结束时,捕获括号的值是来自最外层的值。如果你想获得中间值,可以使用一个标注函数(见下文和pcrecallout文档)。如果上面的模式匹配

 (ab(cd)ef)

内部采集括号(编号2)的值是“ef”,这是在顶层采用的最后一个值。如果捕获子模式在顶层不匹配,即使它在匹配过程中(暂时)设置在更深层次,它的最终捕获值也是未设置的。

如果模式中有超过15个捕获圆括号,PCRE必须在递归期间获得额外的内存来存储数据,这是通过使用pcre_malloc来完成的,然后通过pcre_free释放它。如果无法获得内存,则匹配将失败,并显示PCRE_ERROR_NOMEMORY错误。

不要将(?R)项目与测试递归的条件(R)混淆。考虑这种模式,它匹配尖括号中的文本,允许任意嵌套。嵌套括号中只允许有数字(即递归时),而在外层允许任何字符。

 < (?: (?(R) \d++  | [^<>]*+) | (?R)) * >

在这种模式中,(?(R)是条件子模式的开始,对于递归和非递归情况有两种不同的选择。(?R)项是实际的递归调用。

PCRE和Perl之间递归处理的差异

PCRE中的递归处理与Perl有两个重要的不同之处。在PCRE中(像Python一样,但与Perl不同),递归子模式调用始终被视为原子组。也就是说,一旦匹配了某些主题字符串,即使它包含未尝试的替代方案并且存在随后的匹配失败,也不会重新输入。这可以通过以下方式,其意图匹配包含奇数个字符的字符串回文来说明(例如,"a", "aba", "abcba", "abcdcba"):

 ^(.|(.)(?1)\2)$

它的想法是要么匹配单个字符,要么围绕副回文的两个相同的字符。在Perl中,这种模式起作用;在PCRE中,如果模式长于三个字符则不会。考虑主题字符串“abcba”:

在顶层,第一个字符是匹配的,但由于它不在字符串的末尾,所以第一个选择失败;第二个选择被采用并且递归开始。对子模式1的递归调用成功匹配下一个字符(“b”)。 (请注意,线路测试的开始和结束不是递归的一部分)。

回到顶层,将下一个字符(“c”)与子模式2匹配的内容进行比较,即“a”。这失败了。由于递归被视为原子组,因此现在不存在回溯点,因此整个匹配失败。 (在这一点上,Perl能够重新进入递归并尝试第二种选择。)但是,如果使用其他顺序的替代方法编写模式,则情况会有所不同:

  ^((.)(?1)\2|.)$

这一次,首先尝试递归替代方法,并继续进行递归,直到用完字符,此时递归失败。但是这一次,我们确实有另一种方法来尝试更高的水平。这是最大的区别:在前一种情况下,剩余的选择是在更深的递归级别,PCRE不能使用。

要改变模式,使其匹配所有回文串,而不仅仅是具有奇数字符的模式,很容易将模式更改为:

 ^((.)(?1)\2|.?)$

同样,这在Perl中工作,但不在PCRE中,并且出于同样的原因。当更深的递归匹配单个字符时,不能再次输入以匹配空字符串。解决办法是将这两种情况分开,并在较高级别写出奇数和偶数情况作为备选方案:

^(?:((.)(?1)\2|)|((.)(?3)\4|.))

如果你想匹配典型的回文短语,模式必须忽略所有非单词字符,可以这样做:

 ^\W*+(?:((.)\W*+(?1)\W*+\2|)|((.)\W*+(?3)\W*+\4|\W*+.\W*+))\W*+$

如果使用PCRE_CASELESS选项运行,该模式匹配诸如“A man, a plan, a canal: Panama!”等短语。它在PCRE和Perl中都能很好地工作。请注意使用占有量词* +来避免回溯到非单词字符序列。如果没有这个,PCRE需要花费更长的时间(十次或更多)来匹配典型的短语,并且Perl需要很长时间才会认为它已经进入循环。

注意

上述回文符匹配模式只有在主题字符串不是以比整个字符串短的回文序列开始时才起作用。例如,尽管“abcba”正确匹配,但如果主题是“ababa”,PCRE会在开始时找到回文“aba”,然后在顶层失败,因为字符串的末尾没有出现。再一次,它不能跳回到递归来尝试其他选择,所以整个匹配失败.PCRE和Perl的递归处理有所不同的第二种方式是处理捕获的值。在Perl中,当子模式被递归调用或作为子模式(参见下一节)时,它无法访问在递归之外捕获的任何值。在PCRE中,可以引用这些值。考虑以下模式:

^(.)(\1|a(?2))

在PCRE中,它匹配“bab”。第一个捕获圆括号匹配“b”,然后在第二个组中,当后向引用\1未能匹配“b”时,第二个替代匹配“a”,然后递归。在递归中,\1现在匹配“b”,因此整个匹配成功。在Perl中,该模式无法匹配,因为在递归调用中\1无法访问外部设置的值。

子模式作为子例程

如果递归子模式调用的语法(按数字或按名称)在其引用的括号之外使用,则它在编程语言中像子例程一样运行。被调用的子模式可以在引用之前或之后定义。编号参考可以是绝对的或相对的,如在这些示例中:

 (...(absolute)...)...(?2)...
 (...(relative)...)...(?-1)...
 (...(?+1)...(relative)...

前面的例子指出了该模式

 (sens|respons)e and \1ibility

匹配“意识与感性”和“回应与责任”,但不是“意识与责任”。如果改为模式

(sens|respons)e and (?1)ibility

被使用,它确实匹配“感觉和责任”以及其他两个字符串。另一个例子在上面的DEFINE的讨论中给出。

所有子程序调用,无论是否递归,都被视为原子组。也就是说,一旦一个子程序匹配了一些主题字符串,即使它包含未尝试的替代品并且存在随后的匹配失败,它也不会被重新输入。任何在子程序调用期间设置的捕捉圆括号将在之后恢复为之前的值。

处理选项(如大小写无关)在定义子模式时已修复,所以如果将其用作子例程,则不能为不同的调用更改此类选项。例如,考虑这种模式:

(abc)(?i:(?-1))

它匹配“abcabc”。它与“abcABC”不匹配,因为处理选项的更改不会影响被调用的子模式 (abc)(?i:(?-1))。

标注

Perl有一个功能,使用序列(?{...})可以在匹配正则表达式的过程中遵循任意的Perl代码。除此之外,这可以在重复时提取与同一对括号相匹配的不同子字符串。

PCRE提供了类似的功能,但它当然不能遵守任意的Perl代码。该功能称为“标注”。 PCRE的调用者通过将其入口点放入全局变量pcre_callout(8位库)或pcre[16|32] _callout(16位或32位库)来提供外部函数。默认情况下,该变量包含NULL,它禁用所有调用。

在正则表达式中,(?C)表示要调用外部函数的点。如果要识别不同的标注点,可以在字母C之后放置一个小于256的数字。默认值为零。例如,这种模式有两个标注点:

(?C1)abc(?C2)def

如果将PCRE_AUTO_CALLOUT标志传递给编译函数,则标注将自动安装在模式中的每个项目之前。它们都被编号为255.如果模式中存在条件为断言的条件组,则在该条件之前插入附加的标注。在这个位置也可以设置一个明确的标注,如下例所示:

 (?(?C9)(?=a)abc|def)

请注意,这仅适用于断言条件,而不适用于其他类型的条件。

在匹配期间,当PCRE到达标注点时,调用外部函数。它提供了标注的编号,模式中的位置,以及可选的匹配功能的调用者最初提供的一项数据。标注函数可能会导致匹配继续,回溯或完全失败。

默认情况下,PCRE在编译时和匹配时执行一系列优化,其中一个副作用是跳过标注。如果您需要发生所有可能的标注,则需要设置禁用相关优化的选项。

回溯控制

Perl 5.10引入了一些“特殊回溯控制动词”,这些动词在Perl文档中仍然被描述为“实验性的,可能会在未来版本的Perl中被更改或删除”。它继续说:“应该注意它们在生产代码中的使用,以避免升级过程中出现问题。”本部分描述的PCRE功能也适用相同的说明。

新的动词使用之前无效的语法:左括号后面跟星号。它们通常是形式(* VERB)或(* VERB:NAME)。有些可能采取任何一种形式,根据名称是否存在可能会有不同的表现。名称是不包括右括号的任何字符序列。名称的最大长度在8位库中为255,在16位和32位库中为65535。如果名称为空,即如果右括号紧跟在冒号后面,则效果就好像冒号不在那里。任何数量的这些动词都可能出现在一个模式中。

由于这些动词与回溯特别相关,因此大多数动词只能在使用传统匹配函数中的一种匹配模式时使用,因为这些动词使用回溯算法。除了(* FAIL),其行为类似于失败的否定断言,如果遇到DFA匹配功能,则回溯控制动词会导致错误。

这些动词在重复组,断言和子模式中的行为称为子例程(无论是否递归)在下面进行了说明。

影响回溯动词的优化

PCRE包含一些优化,通过在每次匹配尝试开始时运行一些检查来加速匹配。例如,它可能知道匹配主题的最小长度,或者特定字符必须存在。当这些优化之一绕过匹配运行时,当然不会处理任何包含的回溯动词。您可以通过在调用pcre_compile()或pcre_exec()时设置PCRE_NO_START_OPTIMIZE选项或通过(* NO_START_OPT)启动模式来禁止匹配开始优化。在pcreapi文档中标题为"Option bits for pcre_exec()" 部分有更多关于此选项的讨论。

Perl的实验表明它也有类似的优化,有时会导致异常的结果。

立即行动的Verbs

下列动词一遇到就立即行动。他们可能不会有一个名字。

(*ACCEPT)

该动词使匹配成功结束,跳过模式的其余部分。但是,当它位于被称为子例程的子模式中时,只有该子模式成功结束。然后匹配继续在外层。如果(* ACCEPT)in在肯定断言中触发,则断言成功;在一个否定的断言中,断言失败了。

如果(* ACCEPT)在捕获括号内,则捕获到目前为止的数据。例如:

 A((?:A|B(*ACCEPT)|C)D)

这匹配“AB”,“AAD”或“ACD”;当它匹配“AB”时,“B”被外部圆括号捕获。

 (* FAIL)或(* F)

这个动词导致匹配失败,迫使回溯发生。这相当于(?!),但更易于阅读。 Perl文档指出,它只有在与(?{})或(?? {})结合使用时才有用。这些当然是PCRE中不存在的Perl特性。最接近的等价物是标注功能,例如在此模式中:

a+(?C)(*FAIL)

与字符串“aaaa”的匹配总是失败,但是在每个回溯发生之前采取标注(在本例中为10次)。

记录采取了哪条路径

有一个动词的主要目的是追踪比赛是如何到达的,尽管它也有一个辅助用途,与提高比赛起点一致(见下面的(*跳过))。

(*MARK:NAME) or (*:NAME)

这个动词总是需要一个名字。在一个模式中可能有多少个(* MARK)实例,而且它们的名称不必是唯一的。

当匹配成功时,匹配路径上最后遇到的(* MARK:NAME),(* PRUNE:NAME)或(* THEN:NAME)的名称将返回给调用者,如标题为“ pcreap.exe文档中的“pcre_exec()”的额外数据。这是一个pcretest输出的例子,其中/ K修饰符请求检索和输出(* MARK)数据:

 re> /X(*MARK:A)Y|X(*MARK:B)Z/K
data> XY
  0: XY
 MK: A
 XZ
  0: XZ
 MK: B

在此输出中,(* MARK)名称标记为“MK:”,在此示例中它指示两个替代选项中的哪一个匹配。这是获取这些信息的一种更有效的方式,而不是将每个备选方案放在自己的括号内。

如果在确定的肯定断言中遇到名称为动词的动词,则记录该名称,如果它是最后遇到的则传回。这不会因负面断言或失败而发生。

在部分匹配或匹配失败后,将返回整个匹配过程中最后遇到的名称。例如:  

re> /X(*MARK:A)Y|X(*MARK:B)Z/K
 data> XP
 No match, mark = B

请注意,在这个未锚定的示例中,从主题中字母“X”开始的匹配尝试中保留该标记。后续匹配尝试从“P”开始,然后使用空字符串不会达到(* MARK)项目,但不会重置它。

如果您对匹配失败后的(* MARK)值感兴趣,则应该设置PCRE_NO_START_OPTIMIZE选项(请参见上文)以确保总是尝试匹配。

回溯后的动词

遇到以下动词时什么也不做。匹配继续下面的内容,但如果没有后续匹配,导致动词回溯,则强制失败。也就是说,回溯不能传递到动词的左侧。然而,当这些动词之一出现在一个原子组或者一个真实的断言中时,它的作用就局限于那个组,因为一旦这个组匹配,就永远不会有任何回溯。在这种情况下,回溯可以“跳回”到整个原子组或断言的左侧。 (还要记住,如上所述,这种本地化也适用于子程序调用。)

这些动词在回溯到达时会发生什么样的故障。下面描述的行为是当动词不在子例程或断言中时发生的情况。后续部分涵盖了这些特殊情况。

 (*COMMIT)

如果后面的匹配失败会导致回溯达到该动作,则该动词可能不会后跟名称,从而导致整个匹配失败。即使该模式未被锚定,也不会再尝试通过推进起点来找到匹配。如果(* COMMIT)是唯一遇到的回溯动词,一旦它被传递,pcre_exec()将致力于在当前起点找到一个匹配,或根本没有。例如:

 a+(*COMMIT)b

这匹配“xxaab”,但不匹配“aacaab”。它可以被认为是一种动态的锚,或者“我已经开始了,所以我必须完成”。 (* COMMIT)强制匹配失败时,路径中最近传递的名称(* MARK)将被传回。

如果模式中有多于一个回溯动词,则可能首先触发跟随(* COMMIT)的不同回合(* COMMIT),所以仅仅在匹配时传递(* COMMIT)并不总能保证匹配必须在此起始点。

请注意,除非PCRE的匹配匹配优化被关闭,否则模式开始处的(* COMMIT)与锚点不同,如本paticst示例所示:


  re> /(*COMMIT)abc/
 data> xyzabc
  0: abc
 xyzabc\Y
 No match

PCRE知道任何匹配都必须以“a”开头,因此优化会在运行首次匹配尝试之前沿着主题跳到“a”,这会成功。当优化被第二个主题中的\ Y转义禁用时,匹配从“x”开始,因此(* COMMIT)导致它失败而不尝试任何其他起始点。

 (*PRUNE) or (*PRUNE:NAME)

如果后面的匹配失败导致回溯到达,则此谓词会导致匹配在主题中的当前起始位置失败。如果该模式未被锚定,则正常的“bumpalong”前进到下一个开始字符然后发生。 (* PRUNE)左边可以像往常一样进行回溯,在到达之前或者在(* PRUNE)的右边进行匹配,但是如果没有与右边相匹配,则回溯不能交叉(* PRUNE)。在简单情况下,使用(* PRUNE)只是原子组或占有量词的替代,但是有一些(* PRUNE)用法不能以其他方式表示。锚定模式(* PRUNE)与(* COMMIT)具有相同的效果。

(* PRUNE:NAME)的行为不同于(* MARK:NAME)(* PRUNE)。它就像(* MARK:NAME),因为这个名字被传回给主叫方而被记住。但是,(* SKIP:NAME)只搜索使用(* MARK)设置的名称。

(*SKIP)

这个动词在没有名字的情况下,就像(* PRUNE)一样,除非如果该模式未被锚定,那么“bumpalong”前进不是到下一个字符,而是到了主体中遇到(* SKIP)的位置。 (*跳过)表示无论文本是否匹配导致它都不能成为成功匹配的一部分。考虑:

 a+(*SKIP)b

如果主题是“aaaac ...”,那么在第一次匹配尝试失败后(从字符串中的第一个字符开始),起始点跳转以开始下一次尝试“c”。请注意,所有占用量与本例没有相同的效果;尽管在第一次比赛尝试期间它会抑制回溯,但第二次尝试将从第二个字符开始,而不是跳到“c”。

 (*SKIP:NAME)

当(* SKIP)具有关联名称时,其行为会被修改。当它被触发时,通过模式的前一个路径被搜索到最近的(* MARK),它具有相同的名称。如果找到一个,“bumpalong”前进到对应于(* MARK)的主体位置,而不是到达其中(* SKIP)的位置。如果没有找到匹配名称的(* MARK),则忽略(* SKIP)。

请注意(* SKIP:NAME)仅搜索由(* MARK:NAME)设置的名称。它会忽略由(* PRUNE:NAME)或(* THEN:NAME)设置的名称。

 (* THEN)或(* THEN:NAME)

当回溯达到它时,这个动词导致跳到下一个最内层的选择。也就是说,它取消了当前备选方案中的任何进一步回溯。它的名字源于它可以用于基于模式的if-then-else块的观察:

 ( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ...

如果COND1模式匹配,则尝试FOO(如果FOO成功,可能还有其他项目在组结束后);在失败时,匹配器跳到第二个选择并尝试COND2,而不回溯到COND1。如果成功并且BAR失败,则尝试COND3。如果随后BAZ失败了,那么就没有其他选择了,所以在整个团队之前都会出现回归。如果(* THEN)不在交替内,它就像(* PRUNE)一样。

(* THEN:NAME)的行为与(* MARK:NAME)(* THEN)不同。它就像(* MARK:NAME),因为这个名字被传回给主叫方而被记住。但是,(* SKIP:NAME)只搜索使用(* MARK)设置的名称。

不包含|的子模式性格只是封闭选择的一部分;它不是只有一个选择的嵌套交替。 (* THEN)的作用超出了这样的子模式到封闭的选择。考虑这种模式,其中A,B等是不包含任何|的复杂模式片段这个级别的字符:

 A (B(*THEN)C) | D

如果A和B匹配,但在C中失败,则匹配不会回溯到A;相反,它会移动到下一个替代方案,即D。但是,如果包含(* THEN)的子模式被赋予替代方案,则其行为将有所不同:

 A (B(*THEN)C | (*FAIL)) | D

(* THEN)的效果现在仅限于内部子模式。在C中失败后,匹配移动到(* FAIL),这将导致整个子模式失败,因为没有更多的选择尝试。在这种情况下,匹配现在回溯到A.

请注意,条件子模式不被视为具有两种选择,因为只有一个被使用。换句话说,|条件子模式中的字符具有不同的含义。忽略空白处,请考虑:

 ^.*? (?(?=a) a | b(*THEN)c )

如果主题是“ba”,则此模式不匹配。因为。*?是不确定的,它最初匹配零个字符。条件(?= a)失败,字符“b”匹配,但“c”不匹配。在这一点上,匹配不会回溯到。*?正如也许可以从|的存在预期的那样字符。条件子模式是包含整个模式的单一备选方案的一部分,因此匹配失败。 (如果回溯到。*?,允许它匹配“b”,则匹配将成功。)

刚刚描述的动词在后续匹配失败时提供了四种不同的“控制强度”。

  • (* THEN)是最弱的,在下一个选项中进行比赛。
  • (* PRUNE)接下来,在当前起始位置失败匹配,但允许前进到下一个字符(对于未锚定的模式)。
  • (* SKIP)是相似的,只是前进可以不止一个字符。
  • (* COMMIT)是最强的,导致整个比赛失败。

不止一个回溯动词

如果一个模式中存在多于一个回溯动词,则回溯到第一个动作。例如,考虑以下模式,其中A,B等是复杂模式片段:

 (A(*COMMIT)B(*THEN)C|ABD)

如果A匹配但B失败,则回溯到(* COMMIT )导致整个比赛失败。但是,如果A和B匹配,但C失败,则回溯到(* THEN)会导致下一个替代方案(ABD)被尝试。这种行为是一致的,但并不总是与Perl相同。这意味着如果连续出现两个或更多回溯动词,则最后一个动词不起作用。考虑下面的例子:

 ...(*COMMIT)(*PRUNE)...

如果右边有一个匹配的失败,回溯到(* PRUNE)会导致它被触发,并且它的操作被采用。(* COMMIT)永远不会有回溯。

重复组中的回溯动词

PCRE与Perl在处理重复组中的回溯动词方面不同。例如,考虑:

 /(a(*COMMIT)b)+ac/

如果主题是“abac”,Perl匹配,但是PCRE失败,因为该组的第二次重复中的(* COMMIT)起作用。

断言中的回溯动词

(* FAIL)在一个断言中有其正常的效果:它迫使立即回溯。

(* ACCEPT)在一个肯定的断言中导致断言成功而没有任何进一步的处理。在一个否定的断言中,(* ACCEPT)会导致断言失败,而没有进一步的处理。其他回溯动词如果出现在肯定断言中则不会被专门处理。

特别是,(* THEN)跳到最后一个包含变化的封闭组中的下一个选择,而不管这是否在断言中。然而,负断言是不同的,以确保将肯定断言改变为否定断言改变其断言结果。

回溯到(* COMMIT),(* SKIP)或(* PRUNE)会导致否定断言为真,而不会考虑断言中的任何其他分支。

在子例程中回溯动词

无论是否递归调用子模式,都会发生这些行为。Perl中子程序的处理在某些情况下是不同的。

  • (* FAIL)在子模式中被称为子例程有其正常的效果:它强制立即回溯。
  • (* ACCEPT)作为子例程调用的子模式会导致子例程匹配成功,而无需进一步处理。然后在子程序调用之后继续匹配。
  • (* COMMIT),(* SKIP)和(* PRUNE)在调用子程序的子模式中导致子程序匹配失败。
  • (* THEN)跳转到子模式中具有替代方案的最内部封闭组中的下一个替代方案。如果子模式内没有这样的组,则(* THEN)会导致子程序匹配失败。
Erlang 20

Erlang 是一种通用的面向并发的编程语言,可应付大规模开发活动的程序设计语言和运行环境。

主页 https://www.erlang.org/
源码 https://github.com/erlang/otp
版本 20
发布版本 20.1