组合
用括号表示对正则进行分组,括号内的元字符被看成是一个整体
例子:
匹配 MAC 地址,mac 规则:xx:xx:xx:xx:xx:xx
// 不用组合
let reg1 = /[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}/
// 使用组合
let reg2 = /([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}/
第二个正则表达括号内的 [0-9a-fA-F]{2}:
是一个整体,需要匹配5次
分组与编号
括号在正则中可以用来分组,括号中的子表达式是一个子组
用 JS 来验证分组与编号的规则
let reg = /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})/
let str = '2020-09-18 17:29:00'
reg.exec(str)
上面的匹配结果为
从匹配结果来看,编号为 0 的结果是整个正则表达式的匹配结果,而括号中的子表达式的匹配结果编号则分别是 1 和 2。也就是说,括号中子表达式匹配的结果也会保存下来,如果不想保存某个子表达式的匹配结果,则可以在括号里加前缀 ?:
,如下图
在第二个子表达式添加 ?:
前缀,就不会将子表达式的匹配结果保存下来。
括号嵌套
如果是括号嵌套,那分组的编号又是如何定义的呢?
上面的例子,只是将正则在桥套一些括号
let reg = /((\d{4})-(\d{2})-(\d{2})) ((\d{2}):(\d{2}):(\d{2}))/
结果如图
所以,如果是括号嵌套的话,那么分组的编号规则就是跟树结构差不多,子括号就是相当于子节点,整个正则表达式就是根节点,编号为0。从根节点(整个正则表达式)开始,分配编号 0,然后是左边第一个括号,分配为1,如果左边第一个括号内有子括号,那么以左边第一个括号为根括号,编号为 1,继续遍历子括号并分配编号。这个编号分配规则就跟树的深度遍历是差不多的。
引用
上面已经讲了分组的编号问题,那分组的编号具有什么作用呢?
在使用正则进行匹配或替换时,可以利用 \number
的方式来引用正则的分组,而 JavaScript 的则是利用 $number
来进行引用
正则引用在查找中的使用
JavaScript 的引用在查找使用 **\number**
的。
所以这里使用 PHP 来进行举例
如上图,分组 (\w+)
的编号是1,在正则表达式中, 通过 \1
来对分组1进行引用,达到匹配连续两个相同单次的效果。
注意:引用不是复制正则表达式,而是复制正则表达式匹配的字符串,上述因为是全局匹配,所以匹配两次,上述正则表达式的可以表示为 (cat cat)|(hat hat)
正则引用在替换中使用
JS 中的正则引用替换其实挺使用的,很多时候,我们都需要将 12345678
转换成 12,345,678
这种格式
'12345678'.replace(/(\d)(?=(\d{3})+$)/g, '$1,')
// "12,345,678"