组和反向引用

组将多个模式作为一个整体进行分组,捕获组在使用正则表达式模式与字符串匹配时提供额外的子匹配信息。反向引用指的是正则表达式中先前捕获的组。

试一试

类型

字符 含义
(x)

捕获组: 匹配 x 并记住匹配结果。例如,/(foo)/ 匹配并记住 "foo bar" 中的 "foo"。

正则表达式可以有多个捕获组。在结果中,捕获组的匹配通常在一个数组中,其成员与捕获组中左括号的顺序相同。这通常只是捕获组本身的顺序。当捕获组嵌套时,这变得很重要。可以使用结果元素的索引 ([1], …, [n]) 或预定义的 RegExp 对象的属性 ($1, …, $9) 来访问匹配结果。

捕获组会带来性能损失。如果您不需要记住匹配的子字符串,请优先使用非捕获括号(见下文)。

String.prototype.match() 如果设置了 /.../g 标志,则不会返回组。但是,您仍然可以使用 String.prototype.matchAll() 获取所有匹配结果。

(?<Name>x)

命名捕获组: 匹配 "x" 并将其存储在返回的匹配结果的 groups 属性中,名称由 <Name> 指定。尖括号 (<>) 是组名称所必需的。

例如,要从电话号码中提取美国区号,我们可以使用 /\((?<area>\d\d\d)\)/。结果号码将显示在 matches.groups.area 下。

(?:x)

非捕获组: 匹配 "x" 但不记住匹配结果。无法从结果数组的元素 ([1], …, [n]) 或预定义的 RegExp 对象的属性 ($1, …, $9) 中调用匹配的子字符串。

(?flags:x), (?:flags-flags:x)

修饰符: 仅对包含的模式启用或禁用指定的标志。只有 ims 标志可以在修饰符中使用。

\n

反向引用: 其中 "n" 是一个正整数。匹配正则表达式中第 n 个捕获组匹配的相同子字符串(从左括号开始计数)。例如,/apple(,)\sorange\1/ 匹配 "apple, orange," 中的 "apple, orange,"。

\k<Name>

命名反向引用: 对由 <Name> 指定的命名捕获组最后匹配的子字符串的反向引用。

例如,/(?<title>\w+), yes \k<title>/ 匹配 "Sir, yes Sir" 中的 "Sir, yes Sir"。

注意:\k 在此处按字面意思使用,以指示对命名捕获组的反向引用的开头。

示例

使用组

在此示例中,我们使用捕获组记住结构化格式中的两个单词。\w+ 匹配一个或多个单词字符,括号 () 创建一个捕获组。g 标志用于匹配所有出现。

js
const personList = `First_Name: John, Last_Name: Doe
First_Name: Jane, Last_Name: Smith`;

const regexpNames = /First_Name: (\w+), Last_Name: (\w+)/g;
for (const match of personList.matchAll(regexpNames)) {
  console.log(`Hello ${match[1]} ${match[2]}`);
}

捕获组 参考中查看更多示例。

使用命名组

此示例与上面相同,但我们使用命名捕获组记住匹配的单词。这样,我们可以通过它们的含义访问匹配的单词。

js
const personList = `First_Name: John, Last_Name: Doe
First_Name: Jane, Last_Name: Smith`;

const regexpNames =
  /First_Name: (?<firstname>\w+), Last_Name: (?<lastname>\w+)/g;
for (const match of personList.matchAll(regexpNames)) {
  console.log(`Hello ${match.groups.firstname} ${match.groups.lastname}`);
}

命名捕获组 参考中查看更多示例。

使用组和反向引用

在此示例中,我们首先使用 ['"] 匹配单引号或双引号字符,记住它,使用 .*? 匹配任意数量的字符(*? 是一个 非贪婪量词),直到我们再次匹配记住的引号字符 \1\1 是对第一个捕获组的反向引用,它匹配相同类型的引号。因此,结果将是两个字符串:"'"'"'

js
const quote = `Single quote "'" and double quote '"'`;
const regexpQuotes = /(['"]).*?\1/g;
for (const match of quote.matchAll(regexpQuotes)) {
  console.log(match[0]);
}

反向引用 参考中查看更多示例。

使用组和匹配索引

通过提供 d 标志,将返回每个捕获组的索引。如果您将每个匹配的组与原始文本相关联,这将特别有用——例如,提供编译器诊断。

js
const code = `function add(x, y) {
  return x + y;
}`;
const functionRegexp =
  /(function\s+)(?<name>[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*)/du;
const match = functionRegexp.exec(code);
const lines = code.split("\n");
lines.splice(
  1,
  0,
  " ".repeat(match.indices[1][1] - match.indices[1][0]) +
    "^".repeat(match.indices.groups.name[1] - match.indices.groups.name[0]),
);
console.log(lines.join("\n"));
// function add(x, y) {
//          ^^^
//   return x + y;
// }

另请参阅