JavaScript 正则表达式中的捕获组详解
正则表达式是 JavaScript 中处理字符串的强大工具,而捕获组(capturing groups)则是正则表达式中一个非常重要的概念。本文将深入讲解捕获组的各种用法和特性。
什么是捕获组
捕获组是通过在正则表达式中使用圆括号 () 来定义的。它有两个主要作用:
- 将匹配结果中的特定部分作为独立项提取出来
- 使量词作用于整个组而不仅是前一个字符
基本示例
// 不使用捕获组
console.log('goooo'.match(/go+/)); // 匹配 "goooo"
// 使用捕获组
console.log('gogogo'.match(/(go)+/)); // 匹配 "gogogo"
捕获组在匹配结果中的表现
当使用 str.match(regexp) 方法(不带 g 标志)时,返回的数组会包含完整的匹配和各个捕获组的内容:
let str = '<h1>Hello</h1>';
let result = str.match(/<(.*?)>/);
console.log(result[0]); // "<h1>" - 完整匹配
console.log(result[1]); // "h1" - 第一个捕获组
嵌套捕获组
当捕获组嵌套时,编号是从左到右按开括号的顺序分配的:
let str = '<span class="my">';
let regexp = /<(([a-z]+)\s*([^>]*))>/;
let result = str.match(regexp);
// result[0]: "<span class="my">" (完整匹配)
// result[1]: "span class="my" (外层捕获组)
// result[2]: "span" (标签名)
// result[3]: "class="my"" (属性)
可选捕获组
即使捕获组是可选的(使用了 ? 量词),在结果数组中仍然会保留位置,值为 undefined:
let match = 'a'.match(/a(z)?(c)?/);
console.log(match[1]); // undefined
console.log(match[2]); // undefined
使用 matchAll 获取所有匹配的捕获组
当需要获取所有匹配项及其捕获组时,可以使用 matchAll 方法:
let str = '<h1> <h2>';
let results = str.matchAll(/<(.*?)>/g);
for (let result of results) {
console.log(result[0]); // 完整匹配
console.log(result[1]); // 捕获组内容
}
matchAll 返回一个可迭代对象,而不是数组,这样可以优化性能。
命名捕获组
为了更清晰地引用捕获组,可以使用命名捕获组:
let dateRegexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let str = "2023-05-15";
let result = str.match(dateRegexp);
console.log(result.groups.year); // "2023"
console.log(result.groups.month); // "05"
console.log(result.groups.day); // "15"
在替换中使用捕获组
在字符串替换时,可以引用捕获组:
// 使用编号引用
let str1 = "John Smith";
console.log(str1.replace(/(\w+) (\w+)/, '$2, $1')); // "Smith, John"
// 使用命名引用
let dateStr = "2023-05-15";
console.log(dateStr.replace(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/, '$<day>/$<month>/$<year>')); // "15/05/2023"
非捕获组
如果只需要分组但不需捕获内容,可以使用非捕获组 (?:...):
let str = "Gogogo John!";
let result = str.match(/(?:go)+ (\w+)/);
console.log(result[0]); // "Gogogo John"
console.log(result[1]); // "John"
console.log(result.length); // 2 (没有额外的捕获组)
实际应用示例
域名匹配
let regexp = /([\w-]+\.)+\w+/g;
console.log("site.com my.site.com".match(regexp)); // ["site.com", "my.site.com"]
邮箱验证
let emailRegexp = /[-.\w]+@([\w-]+\.)+[\w-]+/g;
console.log("test@example.com user.name@sub.domain.com".match(emailRegexp));
总结
- 捕获组使用圆括号
()定义,可以提取匹配的子字符串 - 捕获组按从左到右的顺序编号,从 1 开始
- 可以使用命名捕获组
(?<name>...)提高可读性 matchAll方法可以获取所有匹配及其捕获组- 在替换字符串中可以使用
$n或$<name>引用捕获组 - 非捕获组
(?:...)用于只分组不捕获的场景
掌握捕获组的使用可以大大增强正则表达式的功能,使字符串处理更加灵活高效。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



