RegExp.prototype.exec()

exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null

尝试一下

语法

exec(str)

参数

str

要匹配正则表达式的字符串。

返回值

如果匹配失败,exec() 方法返回 null,并将正则表达式的 lastIndex 重置为 0 。

如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的 lastIndex 属性。完全匹配成功的文本将作为返回数组的第一项,从第二项起,后续每项都对应一个匹配的捕获组。数组还具有以下额外的属性:

index

匹配到的字符位于原始字符串的基于 0 的索引值。

input

匹配的原始字符串。

groups

一个命名捕获组对象,其键是名称,值是捕获组。若没有定义命名捕获组,则 groups 的值为 undefined。参阅捕获组以了解更多信息。

indices 可选

此属性仅在设置了 d 标志位时存在。它是一个数组,其中每一个元素表示一个子字符串的边界。每个子字符串匹配本身就是一个数组,其中第一个元素表示起始索引,第二个元素表示结束索引。

描述

在设置了 globalsticky 标志位的情况下(如 /foo/g/foo/y),JavaScript RegExp 对象是有状态的。它们会将上次成功匹配后的位置记录在 lastIndex 属性中。使用此特性,exec() 可用来对单个字符串中的多次匹配结果进行逐条的遍历(包括捕获到的匹配),而相比之下, String.prototype.match() 只会返回匹配到的结果。

在使用 exec() 时,global 标志位不会在 sticky 标志位被设置时生效,而 match() 始终会设置 sticky 标志位。

exec() 是正则表达式的原始方法。许多其它的正则表达式方法会在内部调用 exec()——包括一些字符串方法也会调用 exec(),如 @@replace。虽然 exec() 本身非常强大而又有效,但它通常不能最清楚地表示调用的目的。

示例

使用 exec()

考虑以下示例:

// Match "quick brown" followed by "jumps", ignoring characters in between
// Remember "brown" and "jumps"
// Ignore case
const re = /quick\s(?<color>brown).+?(jumps)/igd;
const result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog');

下表列出这个脚本的返回值(result):

属性
[0] "Quick Brown Fox Jumps"
[1] "Brown"
[2] "Jumps"
index 4
indices [[4, 25], [10, 15], [20, 25]]
groups: { color: [10, 15 ]}
input 4
groups { color: "brown" }

另外,由于正则表达式是全局的(global),re.lastIndex 会被设置为 25

查找所有匹配

当正则表达式设置 g 标志位时,可以多次执行 exec 方法来查找同一个字符串中的成功匹配。当你这样做时,查找将从正则表达式的 lastIndex 属性指定的位置开始。(test() 也会更新 lastIndex 属性)。注意,即使再次查找的字符串不是原查找字符串时,lastIndex 也不会被重置,它依旧会从记录的 lastIndex 开始。

例如,你使用下面的脚本:

const myRe = /ab*/g;
const str = 'abbcdefabh';
let myArray;
while ((myArray = myRe.exec(str)) !== null) {
  let msg = `Found ${myArray[0]}. `;
  msg += `Next match starts at ${myRe.lastIndex}`;
  console.log(msg);
}

脚本运行结果如下:

Found abb. Next match starts at 3
Found ab. Next match starts at 9

警告: 以下情况会导致匹配变成一个无限循环!

  • 不要把正则表达式字面量(或者 RegExp 构造函数)放在 while 条件表达式里。由于每次迭代时 lastIndex 的属性都被重置。
  • 请确保设置了全局(g)标志位,否则 lastIndex 不会被更新。
  • 如果正则表达式可以匹配长度为零的字符(例如:/^/gm),请手动递增 lastIndex,以避免其始终卡在相同的位置。

你也可以将这类的代码替换为 String.prototype.matchAll() 以降低出错的可能性。

结合 RegExp 字面量使用 exec()

你也可以直接使用 exec() 而不是创建一个 RegExp 对象:

const matches = /(hello \S+)/.exec('This is a hello world!');
console.log(matches[1]);

运行上面的代码,控制台会输出 'hello world!' 字符串。

规范

Specification
ECMAScript Language Specification
# sec-regexp.prototype.exec

浏览器兼容性

BCD tables only load in the browser

参见