String.prototype.matchAll()

**matchAll()** 是 String 值的一种方法,它返回一个迭代器,该迭代器包含该字符串与 正则表达式 匹配的所有结果,包括 捕获组

试一试

语法

js
matchAll(regexp)

参数

regexp

一个正则表达式对象,或任何具有 Symbol.matchAll 方法的对象。

如果 regexp 不是 RegExp 对象,并且没有 Symbol.matchAll 方法,则它会使用 new RegExp(regexp, 'g') 隐式转换为 RegExp

如果 regexp 是正则表达式,则它必须设置全局 (g) 标志,否则会抛出 TypeError

返回值

一个 可迭代的迭代器对象(不可重启),包含匹配项,如果未找到匹配项则为空迭代器。迭代器产生的每个值都是一个数组,其形状与 RegExp.prototype.exec() 的返回值相同。

异常

TypeError

如果 regexp 是正则表达式,并且没有设置全局 (g) 标志(其 flags 属性不包含 "g"),则会抛出此异常。

描述

String.prototype.matchAll 的实现本身非常简单 - 它只是简单地调用参数的 Symbol.matchAll 方法,并将字符串作为第一个参数(除了对正则表达式是否为全局进行额外输入验证之外)。实际的实现来自 RegExp.prototype[Symbol.matchAll]()

示例

Regexp.prototype.exec() 和 matchAll()

如果没有 matchAll(),可以使用对 regexp.exec()(以及带有 g 标志的正则表达式)的调用,并在循环中获取所有匹配项

js
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
let match;

while ((match = regexp.exec(str)) !== null) {
  console.log(
    `Found ${match[0]} start=${match.index} end=${regexp.lastIndex}.`,
  );
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.

有了 matchAll(),就可以避免使用 while 循环和带有 g 标志的 exec。相反,您将获得一个迭代器,可以使用更方便的 for...of数组展开Array.from() 结构来使用它

js
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
const matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(
    `Found ${match[0]} start=${match.index} end=${
      match.index + match[0].length
    }.`,
  );
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.

// matches iterator is exhausted after the for...of iteration
// Call matchAll again to create a new iterator
Array.from(str.matchAll(regexp), (m) => m[0]);
// [ "football", "foosball" ]

如果缺少 g 标志,matchAll 会抛出异常。

js
const regexp = /[a-c]/;
const str = "abc";
str.matchAll(regexp);
// TypeError

matchAll 在内部会克隆 regexp - 所以,与 regexp.exec() 不同,lastIndex 不会随着字符串扫描而改变。

js
const regexp = /[a-c]/g;
regexp.lastIndex = 1;
const str = "abc";
Array.from(str.matchAll(regexp), (m) => `${regexp.lastIndex} ${m[0]}`);
// [ "1 b", "1 c" ]

但是,这意味着与在循环中使用 regexp.exec() 不同,您不能修改 lastIndex 来让正则表达式前进或回退。

更好地访问捕获组(比 String.prototype.match() 更好)

matchAll 的另一个令人信服的理由是改进的捕获组访问。

使用带有全局 g 标志的 match() 时,捕获组会被忽略

js
const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";

str.match(regexp); // ['test1', 'test2']

使用 matchAll,您可以轻松访问捕获组

js
const array = [...str.matchAll(regexp)];

array[0];
// ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4]
array[1];
// ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4]

使用带有非正则表达式实现的 [Symbol.matchAll]()matchAll()

如果一个对象具有 Symbol.matchAll 方法,它可以作为自定义匹配器使用。Symbol.matchAll 的返回值将成为 matchAll() 的返回值。

js
const str = "Hmm, this is interesting.";

str.matchAll({
  [Symbol.matchAll](str) {
    return [["Yes, it's interesting."]];
  },
}); // returns [["Yes, it's interesting."]]

规范

规范
ECMAScript 语言规范
# sec-string.prototype.matchall

浏览器兼容性

BCD 表格仅在浏览器中加载

另请参阅