本网站的更多内容 |
简介 |
正则表达式快速入门 |
正则表达式教程 |
替换字符串教程 |
应用程序和语言 |
正则表达式范例 |
正则表达式参考 |
替换字符串参考 |
分支重设群组
Perl 5.10 引进了一项新的正则表达式功能,称为分支重设群组。PCRE 7.2 及更新版本也支持此功能,还有像 PHP、Delphi 和 R 等基于 PCRE 的正则表达式函数的语言。 Boost 在 1.42 版中将其加入 ECMAScript 语法。
交替在分支重置群组内部共享相同的捕获组。语法为 (?|正则表达式)
,其中 (?|
打开群组,而 正则表达式
为任何正则表达式。如果您未在分支重置群组内部使用任何交替或捕获组,则其特殊功能不会发挥作用。它随后会作为 非捕获组 运作。
正则表达式 (?|(a)|(b)|(c))
包含一个具有三个交替选项的分支重置群组。此正则表达式会比对 a
、b
或 c
。正则表达式只有一个编号为 1 的捕获组,由所有三个交替选项共享。比对后,$1
会包含 a
、b
或 c
。
将其与缺乏分支重置群组的正则表达式 (a)|(b)|(c)
进行比较。此正则表达式也会比对 a
、b
或 c
。但它有三个捕获组。比对后,$1
会包含 a
或什么都不包含,$2
会包含 b
或什么都不包含,而 $3
会包含 c
或什么都不包含。
反向引用在分支重置群组内部的捕获组会依照您的预期运作。 (?|(a)|(b)|(c))\1
会比对 aa
、bb
或 cc
。由于分支重置群组内部只有一个交替选项可以比对,因此参与比对的交替选项会决定捕获组保存的文本,进而决定反向引用比对的文本。
分支重设群组中的替代方案不需要有相同数量的捕获组。 (?|abc|(d)(e)(f)|g(h)i)
有三个捕获组。当此正则表达式符合 abc
时,所有三个群组都是空的。当 def
符合时,$1
包含 d
,$2
包含 e
,$3
包含 f
。当 ghi
符合时,$1
包含 h
,而其他两个是空的。
您可以在分支重置群组之前和之后使用捕获组。分支重置群组之前的群组会依通常方式编号。分支重置群组中的群组会从分支重置群组之前的群组继续编号,每个选项都会重设编号。分支重置群组之后的群组会从具有最多群组的选项继续编号,即使那不是最后一个选项。因此 (x)(?|abc|(d)(e)(f)|g(h)i)(y)
定义了五个捕获组。 (x)
是群组 1,(d)
和 (h)
是群组 2,(e)
是群组 3,(f)
是群组 4,以及 (y)
是群组 5。
分支重置群组中的命名捕获组
您可以在分支重置群组中使用 命名捕获组。如果您这样做,您应该对将取得相同编号的群组使用相同的名称。否则,您会在 Perl 或 Boost 中得到不想要的行为。PCRE 仅从版本 8.00 开始可靠地支持分支重置群组中的命名组。这表示 Delphi 仅从 XE7 开始支持,而 PHP 则从版本 5.2.14 开始支持。
(?'before'x)(?|abc|(?'left'd)(?'middle'e)(?'right'f)|g(?'left'h)i)(?'after'y)
与前一个正则表达式相同。它将五个群组命名为「before」、「left」、「middle」、「right」和「after」。请注意,由于第 3 个选项只有一个捕获组,因此那必须是其他选项中第一个群组的名称。
如果您省略某些替代方案中的名称,群组仍会与其他替代方案共用名称。在正则表达式 (?'before'x)(?|abc|(?'left'd)(?'middle'e)(?'right'f)|g(h)i)(?'after'y)
中,群组 (h)
仍命名为「left」,因为分支重设群组使其共用 (?'left'd)
的名称和编号。
在 Perl、PCRE 和 Boost 中,当您希望不同替代方案中的群组拥有相同名称时,最好使用分支重设群组。这是 Perl、PCRE 和 Boost 中确保具有相同名称的群组实际上是同一个群组的唯一方法。
具有准确天数的日期和月份
现在是更实用的范例。这两个正则表达式会比对 m/d 或 mm/dd 格式的日期。它们会排除无效日期,例如 2/31。
^(?:(0?[13578]|1[02])/(3[01]|[12][0-9]|0?[1-9]) # 31 天
| (0?[469]|11)/(30|[12][0-9]|0?[1-9]) # 30 天
| (0?2)/([12][0-9]|0?[1-9]) # 29 天
)$
第一个版本使用 非捕获组 (?:…)
来群组选项。它有六个独立的捕获组。 $1
和 $2
保留 31 天月份的月份和日期。 $3
和 $4
保留 30 天月份的月份和日期。 $5
和 $6
仅用于二月。
^(?|(0?[13578]|1[02])/(3[01]|[12][0-9]|0?[1-9]) # 31 天
| (0?[469]|11)/(30|[12][0-9]|0?[1-9]) # 30 天
| (0?2)/([12][0-9]|0?[1-9]) # 29 天
)$
第二个版本使用分支重置群组 (?|…)
来群组备选项并合并其捕获组。这两个正则表达式的第 4 个字符是唯一的不同。现在只有两个捕获组。它们在树状备选项之间共用。当找到一个符合项时,$1
永远包含月份,而 2
永远包含日期,与月份中的天数无关。