分组的概念
在一个正则表达式中, 通过英文()
包裹的内容, 就对应着一个分组, 如下正则表达式, 就包含了两个分组
/a-z(\d+)a-z(\d+)/
分组的排序
一般来说, 分组都是从1开始排序的, 不过,也有编号为0的分组,它是默认存在的,对应整个表达式匹配的文本
也就是说, 整个正则表达式所匹配到的文本, 就对应着分组0
, 而我们显示指定的分组, 都是从1开始排序的
那么如果我们的分组中包含有嵌套分组呢, 也就是一个分组里面包含多个子分组, 子分组又可以继续包含子分组
这个时候顺序是怎么算的呢, 其实也很简单:
无论括号如何嵌套,分组的编号都是根据开括号出现顺序来计数的;开括号是从左向右数起第多少个开括号,整个括号分组的编号就是多少
参考下面的图片, 引用自<正则指引第二版>
捕获分组
括号不仅能把元素进行分组, 当正则表达式匹配完成之后, 还会保留分组匹配的结果, 所以在匹配完成之后, 可以通过对应的分组编号来获取匹配的结果,
所以这种功能叫做捕获分组
, 对应的, 这种括号叫做捕获型括号
示例
// javascript code
"http://www.baidu.com".match(/(\w+):\/\/(\w+\.\w+\.\w+)/);
// 会返回如下的结果
0: "http://www.baidu.com"
1: "http"
2: "www.baidu.com"
groups: undefined
上面的代码可以体现出来, 索引0对应的就是整个匹配到的部分, 而索引1对应第一个分组, 也就是协义部分, 索引2对应着第二个分组, 也就是域名部分
非捕获分组
上面讲了捕获分组, 他的作用就是在匹配之后会保留匹配结果, 而非捕获分组则相反, 只分组, 但是不保留匹配结果,
同时他也不会影响分组排序, 排序的时候会忽略非捕获分组
语法: (?:...)
只需要在开括号后紧跟一个?
和:
即可, 我们再用上面的代码示例一下
// javascript code
"http://www.baidu.com".match(/(?:\w+):\/\/(\w+\.\w+\.\w+)/);
// 会返回如下的结果
0: "http://www.baidu.com"
1: "www.baidu.com"
groups: undefined
可以看到, 这次没有保留协义部分的匹配结果, 同时也没有影响匹配顺序
命名分组
捕获分组一般通过数组编号来引用匹配的内容, 虽然是从左到右来计算编号, 但是分组多了也难免混淆,因此可以采用对分组命名的方式来使分组更直观
由于在不同的语言语法不一, 下面我们分开来说
javascript
语法: (?<name>)
"http://www.baidu.com".match(/(?<protocol>\w+):\/\/(?<domain>\w+\.\w+\.\w+)/);
// 返回结果
0: "http://www.baidu.com"
1: "http"
2: "www.baidu.com"
groups:
domain: "www.baidu.com"
protocol: "http"
可以看到, groups
现在不再是undefined
了, 而是包含了两个我们自定义的分组名
同样也可以发现, 我们对分组命名之后, 数字编号对应的匹配内容也同时保留了
PHP
下面来看一下在php
中使用命名分组
语法: (?<name>)
或者 (?P<name>)
或 (?'name')
// pattern中, protocol采用了 (?<name>)方式, domain采用了 (?P<name>)方式
$pattern = "/(?<protocol>\w+):\/\/(?P<domain>\w+\.\w+\.\w+)/";
preg_match_all($pattern, "http://www.baidu.com", $matches);
print_r($matches);
//结果
Array
(
[0] => Array
(
[0] => http://www.baidu.com
)
[protocol] => Array
(
[0] => http
)
[1] => Array
(
[0] => http
)
[domain] => Array
(
[0] => www.baidu.com
)
[2] => Array
(
[0] => www.baidu.com
)
)
可以看到, php也一样同时保留了分组编号和分组名称对应的匹配内容
关于php的命名分组语法:
在 PHP 4.3.3 中,可以对子组使用 (?P
pattern) 的语法进行命名。 这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现, PHP 5.2.2中又增加了两种味子组命名的语法: (?pattern) 和 (?’name’pattern)。
参考php官方文档: https://www.php.net/manual/zh/regexp.reference.subpatterns.php
Python
语法: (?P<name>)
参考
- 《正则指引 第二版》
不多说了, 就这样吧