深入理解JS正则表达式:捕获与非捕获分组的区别
本文深入解析JavaScript正则表达式中的分组机制,重点区分捕获性分组与非捕获性分组。通过对比(\d+)与(\d)+在贪婪模式下的匹配差异,揭示分组捕获最后一次迭代结果的原理,并介绍(?:pattern)非捕获语法的应用,帮助开发者避免常见正则陷阱。
深入理解JS正则表达式:捕获与非捕获分组的区别
深入理解JS正则表达式---分组
此前曾撰写过一篇关于正则表达式入门的文章,自认为对正则已有一定掌握,但今日又遇到了一个意想不到的问题,或许源于自身不够细致。本文将重点分享JavaScript正则表达式中关于“分组”的知识。若你对JS正则表达式尚不熟悉,可点击此处了解更多基础知识。
分组在正则表达式中的应用十分广泛。从我的理解来看,分组即由一对括号()表示,每一对括号定义一个独立的分组。分组主要可以分为两类:
• 捕获性分组 • 非捕获性分组
捕获性分组及其匹配原理
捕获性分组
在诸如 match 或 exec 等函数中,捕获性分组的结果会以数组的第二项、第三项等形式返回。我们先来看一个具体示例:
var reg = /test(\d+)/;
var str = 'new test001 test002';
console.log(str.match(reg));//["test001", "001", index: 4, input: "new test001 test002"]
在代码中,(\d+) 构成一个分组(部分人也称之为子模式),两者含义相同。在上述示例中,test001 是完全匹配的结果。然而,分组的匹配是从整个完全匹配结果(即 test001)中查找与子模式 \d+ 相匹配的字符,此处显然为 001。但今天遇到的情况有所不同:
var reg = /test(\d)+/;
var str = 'new test001 test002';
console.log(str.match(reg));//["test001", "1", index: 4, input: "new test001 test002"]
主要区别在于 (\d+) 改为了 (\d)+。整个匹配结果依然是 test001,但第一个分组匹配到的结果却发生了变化。我们将逐步分析两者的区别。
在 (\d+) 的情况下,整个表达式作为一个分组。由于默认情况下匹配模式为贪婪模式,即尽可能多地匹配 \d+ 所能匹配到的结果,因此匹配结果为 001。外层添加的一对括号构成了一个分组,故第一个分组中捕获的结果即为 001。再看第二个示例中的 (\d)+,这同样属于贪婪模式。首先它会匹配字符 0,随后继续匹配 0,最后匹配 1,匹配过程在此结束。表面上看,这与第一个示例的匹配结果似乎没有区别,但这里的分组 (\d) 表示匹配单个数字。按照之前的理解,似乎应该捕获第一个数字 0,但这种理解是错误的。由于整个匹配过程遵循贪婪模式,尽可能多地匹配分组中的 (\d),因此最终捕获的是最后一次匹配到的结果,即 1。如果是非贪婪模式,则会尽可能少地匹配。
var reg = /test(\d)+?/;
var str = 'new test001 test002';
console.log(str.match(reg));//["test001", "0", index: 4, input: "new test001 test002"]
因此,当使用 (\d) 且为非贪婪模式时,匹配结果为 0。尽管后面仍有可匹配的结果,但此处遵循尽可能少匹配的原则。
非捕获性分组的应用
非捕获性分组
非捕获性分组指的是在某些场景下需要使用一对括号,但不希望其成为捕获性分组,即不希望该分组被 match、exec 等函数获取。通常,在括号内部前面加上 ?:,即写成 (?:pattern),即可将其变为非捕获性分组。
var reg = /test(?:\d)+/;
var str = 'new test001 test002';
console.log(str.match(reg));//["test001", index: 4, input: "new test001 test002"]
采用这种方式后,match 的结果中将不再包含分组匹配到的内容,即数组中少了第二项的 1。
本文着重说明 (\d+) 和 (\d)+ 的区别,这也是我今天遇到的一个陷阱。若有错误之处,欢迎指正。
以上这篇深入理解JS正则表达式---分组就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
