捕获和分组

分组和捕获


分组是将正则表达式中的一部分放在小括号()之内,从而将该部分组合在一起。分组内的正则表达式匹配的内容是连续的一个整体,比如说 /foot(ball)/ 可以也只能匹配football。和[]不同,[]里的正则不是连续的一个整体,比如/foot[ball]/ ,其中[ball]里面的每个字符是或的关系,它可以匹配的footbfootafootl,如果再加上量词+ /foot[ball]+/ 可以匹配foot后面跟着的bal三个字符的任意组合。

下面回归到分组。分组内的正则是一个整体,如果想要可选分支,可以使用竖线来实现。比如/foot(ball|age)/ 可以匹配 football或者footage。如果我们不使用(),则/football|age/ 只能匹配football或者 age。这就是分组的其中的一个作用。

分组的第二个作用就是捕获。在()中的正则匹配到的字符串会被保存起来,在正则表达式中可以继续引用这部分被捕获的字符串(反向引用)。被捕获的内容的下标从1开始计数。/foot(ball)/匹配字符串football 成功以后,下标0是整个正则表达式匹配到的内容,下标1是由()捕获的内容ball。对于下标的计数方式,遵循的原则是:嵌套从外到内,并列从左到右。什么意思呢,分组是可以嵌套的,如果正则中有分组嵌套分组的情形,那最外层的分组要先开始计数。并列的从左到右很好理解了,左边的要先于右边的。下面我们看/((foot|basket)(ball))/ 匹配字符串football。最外层的分组下标为1,内容是football,里层分组遵循从左至右原则,下标2为foot,下标3为ball。这里需要注意的是嵌套的优先级要高于并列的。就相当于深度遍历。如果一个分组1嵌套的有分组2,并且在分组1的右边并列又个分组3,则分组2的下标要先于分组3。/((foot|basket)(ball))\s(ok)/ 匹配字符串football ok,分组((foot|basket)(ball))的下标不会变,(ok)的下标是4。

<?php
$str = "football ok";

$pattern = "/((foot|basket)(ball))\s(ok)/";

$res = preg_match($pattern,$str,$matches);

print_r($matches);

执行结果

Array
(
    [0] => football ok
    [1] => football
    [2] => foot
    [3] => ball
    [4] => ok
)

注: 捕获分组的最大下标序号是65535,也就是说最大可以有65535个分组。然而现实中我们不会在一个正则表达式中使用这么多的分组。

既然分组可以对分组内匹配到的字符串进行捕获,那如果我们仅仅是对正则进行分组,而不对其捕获,这也是可以的。非捕获分组形式为(?:)。对于上面的例子,如果不想捕获football,可以修改正则为/(?:(foot|basket)(ball))\s(ok)/

<?php

$str = "football ok";

$pattern = "/(?:(foot|basket)(ball))\s(ok)/";

$res = preg_match($pattern,$str,$matches);

print_r($matches);

再看执行结果 football 就不会被捕获了。

Array
(
    [0] => football ok
    [1] => foot
    [2] => ball
    [3] => ok
)

在PHP中,对于分组(不管是捕获还是非捕获),还提供了另一种功能。可以给分组单独指定模式修饰符。在分组的开始部分加上(?修饰符)。 捕获分组形式((?修饰符)regex);非捕获分组形式(?:(?修饰符)regex)。 对于非捕获分组还有另一种形式,就是在 ?: 之间加修饰符——(?修饰符:)。 例如让foot或者basket不区分大小写,/(((?i)foot|basket)(ball))\s(ok)/

<?php

$str = "FOOtball ok";

$pattern = "/(((?i)foot|basket)(ball))\s(ok)/";

$res = preg_match($pattern,$str,$matches);

print_r($matches);

匹配结果

Array
(
    [0] => FOOtball ok
    [1] => FOOtball
    [2] => FOOt
    [3] => ball
    [4] => ok
)

非捕获两种形式

<?php

$str = "FOOtball ok";

$pattern = "/((?:(?i)foot|basket)(ball))\s(ok)/";
// 或者 "/((?i:foot|basket)(ball))\s(ok)/"

$res = preg_match($pattern,$str,$matches);

print_r($matches);

执行结果

Array
(
    [0] => FOOtball ok
    [1] => FOOtball
    [2] => ball
    [3] => ok
)

捕获内容的命名


对于捕获的内容除了使用下标进行索引之外,PHP还提供了给捕获命名的功能。语法形式为(?<name>)或者(?'name')/((?<type>foot|basket)(ball))\s(ok)/ 给分组命名为type。那么除了对捕获的内容进行下标索引之外,还能使用键名进行关联。

<?php

$str = "football ok";

$pattern = "/((?<type>foot|basket)(ball))\s(ok)/";

$res = preg_match($pattern,$str,$matches);

print_r($matches);

执行结果

Array
(
    [0] => football ok
    [1] => football
    [type] => foot
    [2] => foot
    [3] => ball
    [4] => ok
)

查看笔记

扫码一下
查看教程更方便