PHP 中多个 Subpattern 匹配问题

今天无意中看到多个小括号嵌套的正则表达式. 突然就想, 那么匹配出来后的排序是怎么样的? 于是决定看一下文档.
文档地址: https://www.php.net/manual/en/regexp.reference.subpatterns.php

什么是子模式 (Subpattern)

子模式通过小括号来界定. 它有两个作用:

  1. 局部化一组可替代方案. 例如: (sun|mon)day, 既匹配 sunday, 也匹配 monday. 如果不用小括号的写法是 sunday|monday.
  2. 它建立一组可捕捉的子模式. 当整个模式匹配时, 匹配子模式的字符串通过参数传回给调用者(像 preg_match 中的 match参数). match 是个数组. 它从左到右按开括号的顺序数, (从1开始) 去获取捕捉字符串的数量.

例如:

1
2
字符串 "the red king" 匹配模式 ((red|white)(king|queen)). 
捕捉子字符串就是 "red king", "red", "king". 下标分别是 1, 2, 3

再来看一个例子:

1
2
3
模式是 /((Sat)ur|(Sun))day/
匹配字符串 Saturday 的结果是, 捕捉子字符串分别是 1 => Satur, 2 => Sat
匹配字符串 Sunday 的结果是, 捕捉子字符串分别是 1 => Sun, 2 => '', 3 => Sun

仔细想想为什么?

数量限制

捕捉子字符串最多 65535 个. 不过一般不会到这个上限. 应该能满足大多数的需要.

如何关闭捕捉子模式?

有的时候, 我们可能只想使用它的多组替代方案的功能(上面第1点), 而不想使用它的捕捉功能(上面第2点). 那该怎么做呢?
如果在左小括号后, 紧跟 “?:” 字符, 那么子模式不再时行捕捉, 并且在计算子模式的捕捉子序列时也不再计数.

例如:

1
2
((?:red|white)(king|queen)) 匹配字符串 white queen 时,
子模式匹配的子序列分别是: white queen, queen, 下标分别为1,2

可互相替代的组号

有时候需要有多个匹配的子模式, 但是他们的子组号可互相替代, 就是子组号要一样.
正常情况下, 每个子模式都会有一个后向引用的组号, 即使它们当中只有一个子模式会被匹配到.
解决这个问题, 需要 “?|”, 它允许产生重复的组号

比如:

1
(?:(Sat)ur|(Sun))day 匹配 Sunday, 子模式的匹配序列为: 1 => '', 2 => Sun

这里 Sun 的序号是2, 即使1是空的.
使用 ?| 后:
1
2
(?|(Sat)ur|(Sun))day 匹配 Sunday, 子模式的匹配序列为: 1 => Sun
(?|(Sat)ur|(Sun))day 匹配 Saturday, 子模式的匹配序列为: 1 => Sat

使用 ?| , Sat 和 Sun 的后向引用都是 1.