分组的概念
在一个正则表达式中, 通过英文()包裹的内容, 就对应着一个分组, 如下正则表达式, 就包含了两个分组
/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
语法: (?)
"http://www.baidu.com".match(/(?\w+):\/\/(?\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中使用命名分组
语法: (?) 或者 (?P) 或 (?'name')
// pattern中, protocol采用了 (?)方式, domain采用了 (?P)方式
$pattern = "/(?\w+):\/\/(?P\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 中,可以对子组使用 (?Ppattern) 的语法进行命名。 这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现, PHP 5.2.2中又增加了两种味子组命名的语法: (?pattern) 和 (?’name’pattern)。
Python
语法: (?P)
参考
《正则指引 第二版》
不多说了, 就这样吧