PCRE正则语法
在线手册:中文 英文
PHP手册

子组(子模式)

子组通过圆括号分隔界定, 并且它们可以嵌套. 将一个模式中的一部分标记为子组(子模式)主要是来做两件事情:

  1. 将可选分支局部化. 比如, 模式cat(arcat|erpillar|)匹配”cat”, “cataract”, “caterpillar”中的一个, 如果没有圆括号的话, 它匹配的则是”cataract”, “erpillar”以及空字符串.

  2. 将子组设定为捕获子组(向上面定义的). 当整个模式匹配后, 目标字符串中匹配子组的部分将会通过pcre_exec()()ovector参数回传给调用者. 左括号从左至右出现的次序就是对应子组的下标(从1开始), 可以通过这些下标数字来获取捕获子模式匹配结果.

比如, 如果字符串”the red king”使用模式((red|white) (king|queen))进行匹配, 模式匹配到的结果是array(“red king”, ”red king”, “red”, “king”)的形式, 其中第0个元素是整个模式匹配的结果, 后面的三个元素依次为三个子组匹配的结果. 它们的下表分别为1, 2, 3.

事实上, 圆括号履行的两种功能并不总是有用的. 经常我们会有一种需求需要使用子组进行分组, 但又不需要(单独的)捕获它们. 在子组定义的左括号后面紧跟字符串”?:”会使得该子组不被单独捕获, 并且不会对其后子组序号的计算产生影响. 比如, 如果字符串”the white queen”匹配模式((?:red|white) (king|queen)), 匹配到的结果会是array(“white queen”, “white queen”, “white queen”), 只捕获了最外面的和king|queen这两个子组. 捕获子组序号的最大值是99, 最大允许拥有的所有子组(包括捕获的和非捕获的)的最大数量为200.

为了方便简写, 如果需要在非捕获子组开始位置设置选项, 选项字母可以位于?和:之间, 比如:

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

上面两种写法实际上是相同的模式. 因为可选分支会从左到右尝试每个分支, 并且选项没有在子模式结束前被重置, 并且由于选项的设置会穿透对后面的其他分支产生影响, 因此, 上面的模式都会匹配”SUNDAY”以及”Saturday”

在php 4.3.3中, 可以对子组使用(?P<name>pattern)的语法进行命名. 这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现. php 5.2.2中又增加了两种味子组命名的语法: (?<name>pattern)(?’name’pattern)

有时需要多个匹配可以在一个正则表达式中选用子组. 为了让多个子组可以共用一个后向引用数字的问题, (?|语法允许复制数字. 考虑下面的正则表达式匹配Sunday:

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

这里当后向引用1空时Sun存储在后向引用2中. 当后向引用2不存在的时候Sat存储在后向引用1中. 使用 (?|修改模式来修复这个问题:

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

使用这个模式, SunSat都会被存储到后向引用1中.


PCRE正则语法
在线手册:中文 英文
PHP手册
PHP手册 - N: 子组(子模式)

用户评论:

Chris (01-Feb-2010 04:51)

For instance, one of my rewrite rules for a project I'm working on is "replace o with ? if o is the next to last vowel and even numbered (counting left to right)"

So, an example is:

heabatoik would become heabat?ik (o is the next to last vowel, as well as the 4th vowel)

habatoik would not change (o is the next to last vowel, but is the 3rd vowel)

$str = preg_replace(
  '/^((?:[^aeiou]*[aeiou]){2})+' .
    '([^aeiou]*[aeiou][^aeiou]*)' .
    'o' .
    '(?=[^aeiou]*[aeiou][^aeiou]*$)/',
  '$1$2?',
  'heabatoik');