使用 String.prototype.matchAll() 更好地匹配结果

Joe Medley
Joe Medley

Chrome 73 引入了 String.prototype.matchAll() 方法。它的行为与 match() 类似,但会返回一个迭代器,其中包含全局或粘性正则表达式中的所有正则表达式匹配。这样可以轻松迭代匹配项,尤其是当您需要访问捕获组时。

match() 有什么问题?

简短回答是没有任何影响,除非您尝试返回包含捕获组的全局匹配。下面是一个编程题目,供您参考。请考虑以下代码:

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const results = string.match(regex);
console.log(results);
// → ['test1', 'test2']

在控制台中运行此代码,您会发现它会返回一个包含字符串 'test1''test2' 的数组。如果我从正则表达式中移除 g 标志,则会得到包含所有捕获组的结果,但我只会得到第一个匹配项。如下所示:

['test1', 'e', 'st1', '2', index: 0, input: 'test1test2', groups: undefined]

此字符串包含第二个可能匹配的字符串,以 'test2' 开头,但我没有它。现在,问题来了:如何获取每个匹配项的所有捕获组?“String.prototype.matchAll() 提案”说明介绍了两种可能的方法。我不会详细介绍这些步骤,因为希望您很快就不需要它们了。

String.prototype.matchAll()

matchAll() 的说明示例会是什么样的?看一看就知道了。

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const matches = string.matchAll(regex);
for (const match of matches) {
  console.log(match);
}

关于此事,有几点需要注意。与在全局搜索中返回数组的 match() 不同,matchAll() 会返回一个迭代器,该迭代器可与 for...of 循环完美配合使用。迭代器会为每个匹配生成一个数组,包括包含一些附加信息的捕获组。如果您将这些内容输出到控制台,它们将如下所示:

['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', groups: undefined]
['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined]

您可能会注意到,每个匹配项的值都是一个数组,其格式与 match() 针对非全局正则表达式返回的格式完全相同。

奖励内容

本课程主要面向刚接触正则表达式或对正则表达式不熟悉的用户。您可能已经注意到,match() 和 matchAll() 的结果(对于每次迭代)都是包含一些额外命名属性的数组。在准备这篇文章时,我发现 MDN 上对这些属性的文档存在一些缺陷(我已修正)。下面是简要说明。

index
原始字符串中第一个结果的索引。在上面的示例中,test2 从位置 5 开始,因此 index 的值为 5。
input
matchAll() 针对其运行的完整字符串。在我的示例中,该值为 'test1test2'
groups
包含正则表达式中指定的任何命名捕获组的结果。

总结

如果我遗漏了任何信息,请在下方留言告诉我。如需详细了解 JavaScript 近期的变化,请参阅之前的更新V8 网站