JavaScript 正则表达式中的分组捕获技术详解
正则表达式是 JavaScript 中处理字符串的强大工具,而分组捕获则是正则表达式中一个极其重要的功能。本文将深入讲解 JavaScript 正则表达式中的分组技术,帮助开发者更好地掌握这一功能。
什么是分组捕获
在正则表达式中,使用圆括号 ()
可以将部分模式组合在一起,形成一个分组。这种分组有两个主要作用:
- 将匹配到的内容单独提取出来,便于后续处理
- 对分组内的整个内容应用量词(如
+
,*
,?
等)
基础分组示例
简单重复匹配
考虑一个简单的例子,我们想匹配连续的 "go" 字符串:
console.log('Gogogo now!'.match(/(go)+/ig)); // 输出 ["Gogogo"]
这里 (go)+
表示匹配一个或多个连续的 "go" 字符串,而不只是匹配 "g" 后面跟着多个 "o"。
域名匹配
更实用的例子是匹配网站域名:
const domainRegex = /(\w+\.)+\w+/g;
console.log("site.com my.site.com".match(domainRegex));
// 输出 ["site.com", "my.site.com"]
这个正则表达式可以匹配多级域名,但需要注意它无法匹配包含连字符的域名(如 "my-site.com"),因为 \w
不包含连字符。
分组内容的获取
当使用 match()
方法(不带 g
标志)时,返回的数组会包含完整匹配和各个分组的内容:
const str = '<h1>Hello, world!</h1>';
const tag = str.match(/<(.*?)>/);
console.log(tag[0]); // 输出 "<h1>" (完整匹配)
console.log(tag[1]); // 输出 "h1" (第一个分组内容)
嵌套分组处理
分组可以嵌套使用,每个分组按左括号出现的顺序编号:
const str = '<span class="my">';
const regexp = /<(([a-z]+)\s*([^>]*))>/;
const result = str.match(regexp);
console.log(result[0]); // 完整匹配: <span class="my">
console.log(result[1]); // 第一分组: span class="my"
console.log(result[2]); // 第二分组: span
console.log(result[3]); // 第三分组: class="my"
可选分组处理
即使分组是可选的(使用 ?
量词),结果数组中对应的位置仍然存在,值为 undefined
:
const match = 'a'.match(/a(z)?(c)?/);
console.log(match.length); // 3
console.log(match[0]); // "a"
console.log(match[1]); // undefined
console.log(match[2]); // undefined
使用 matchAll 获取所有匹配的分组
当需要获取所有匹配项及其分组时,可以使用 matchAll()
方法:
const str = '<h1> <h2>';
const results = str.matchAll(/<(.*?)>/g);
for (const result of results) {
console.log(result[0]); // 完整匹配
console.log(result[1]); // 分组内容
}
matchAll()
返回一个可迭代对象,每个匹配项都是一个包含完整匹配和分组内容的数组。
命名分组
为了提高代码可读性,ES2018 引入了命名分组:
const dateRegexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const str = "2019-04-30";
const groups = str.match(dateRegexp).groups;
console.log(groups.year); // "2019"
console.log(groups.month); // "04"
console.log(groups.day); // "30"
分组在替换中的应用
分组内容可以在替换字符串中引用:
let str = "John Bull";
console.log(str.replace(/(\w+) (\w+)/, '$2, $1')); // "Bull, John"
// 使用命名分组
const dateStr = "2019-10-30";
console.log(dateStr.replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
'$<day>.$<month>.$<year>'
)); // "30.10.2019"
非捕获分组
如果只需要分组但不需捕获内容,可以使用 ?:
前缀:
const str = "Gogogo John!";
const regexp = /(?:go)+ (\w+)/i;
const result = str.match(regexp);
console.log(result[0]); // "Gogogo John"
console.log(result[1]); // "John"
console.log(result.length); // 2 (没有 go 的捕获项)
总结
正则表达式的分组功能非常强大,主要特点包括:
- 使用
()
创建分组,可以嵌套使用 - 分组内容可以通过
match()
或matchAll()
获取 - ES2018 引入命名分组,提高代码可读性
- 分组内容可用于替换操作
- 使用
?:
创建非捕获分组,不保留匹配内容
掌握这些分组技术将大大提升你处理复杂字符串模式的能力,使正则表达式更加灵活和强大。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考