使用 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 循环配合使用。迭代器会为每个匹配项生成一个数组,包括带有一些 extra 的捕获组。如果将它们输出到控制台,它们将如下所示:

['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
包含正则表达式中指定的任何已命名的捕获组的结果。

总结

如果有任何遗漏之处,请在下面的评论部分告诉我们。您可以参阅过往更新中或访问 V8 网站,详细了解 JavaScript 的近期变更。