徐善通的随笔

千里之行, 始于足下



正则表达式之分组的用法


分组的概念

在一个正则表达式中, 通过英文()包裹的内容, 就对应着一个分组, 如下正则表达式, 就包含了两个分组

/a-z(\d+)a-z(\d+)/

分组的排序

一般来说, 分组都是从1开始排序的, 不过,也有编号为0的分组,它是默认存在的,对应整个表达式匹配的文本

也就是说, 整个正则表达式所匹配到的文本, 就对应着分组0, 而我们显示指定的分组, 都是从1开始排序的

那么如果我们的分组中包含有嵌套分组呢, 也就是一个分组里面包含多个子分组, 子分组又可以继续包含子分组

这个时候顺序是怎么算的呢, 其实也很简单:

无论括号如何嵌套,分组的编号都是根据开括号出现顺序来计数的;开括号是从左向右数起第多少个开括号,整个括号分组的编号就是多少

参考下面的图片, 引用自<正则指引第二版>

alt

捕获分组

括号不仅能把元素进行分组, 当正则表达式匹配完成之后, 还会保留分组匹配的结果, 所以在匹配完成之后, 可以通过对应的分组编号来获取匹配的结果,

所以这种功能叫做捕获分组, 对应的, 这种括号叫做捕获型括号

示例

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

参考php官方文档: https://www.php.net/manual/zh/regexp.reference.subpatterns.php

Python

语法: (?P<name>)

参考

  • 《正则指引 第二版》

不多说了, 就这样吧


作者: 徐善通
地址: https://www.xstnet.com/article-150.html
声明: 除非本文有注明出处,否则转载请注明本文地址


我有话说



最新回复


正在加载中....

Copyrights © 2016-2019 醉丶春风 , All rights reserved. 皖ICP备15015582号-1