You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

String.prototype.matchAll()是否可返回重叠正则匹配结果?

能否让String.prototype.matchAll()返回重叠匹配结果?

问题背景

我尝试给String.prototype.matchAll()传入正则表达式,希望它返回重叠的匹配结果,但所有思路都只能得到非重叠的匹配项。测试代码如下:

function logMatches(str, re) {
  console.log(`"${str}".matchAll(/${re.source}/${re.flags}) = [`);
  [...str.matchAll(re)].map(matchProperties).forEach((props) => {
    console.log("	", props);
  })
  console.log("];");
  console.log();
}

function matchProperties(match) {
  return "{ " + (Object.getOwnPropertyNames(match).map((propName) => {
    return propName + ": " + JSON.stringify(match[propName])
  }).join(", ")) + " }, // Note: this element is an Array";
}

logMatches("foo bar baz", /foo|baz/g); // no overlap expected
logMatches("foo bar baz", / .*/g);
logMatches("foo bar baz", /b.*/g);
logMatches("foo bar baz", /b.*?/g);  // no overlap expected
logMatches("foo bar baz", /ba.*$/g);
logMatches("foo bar baz", /ba| .* /g);

我期望最后一个示例返回包含重叠匹配的结果:

"foo bar baz".matchAll(/ba| .* /g) = [
     { 0: " bar ", length: 1, index: 3, input: "foo bar baz", groups: undefined }, // Note: this element is an Array
     { 0: "ba", length: 1, index: 4, input: "foo bar baz", groups: undefined }, // Note: this element is an Array
     { 0: "ba", length: 1, index: 8, input: "foo bar baz", groups: undefined }, // Note: this element is an Array
];

原因分析

这是正则表达式的通用特性,既不是matchAll的工作机制问题,也不是你的示例代码有bug。

正则引擎默认采用非重叠匹配逻辑:每次匹配成功后,会从当前匹配结果的结束位置开始下一次匹配,不会回溯到之前的位置寻找重叠的结果。比如你最后一个例子里的/ba| .* /g:

  1. 第一次匹配到" bar "(索引3到7),下一次匹配直接从索引7开始;
  2. 索引7之后只有"baz",所以只能匹配到索引8的"ba",不会回到索引4去匹配重叠的"ba"。

实现重叠匹配的方法

如果要得到重叠的匹配结果,需要借助零宽度断言(比如正向预查(?=...))。零宽度断言不会"消耗"字符串中的字符,匹配成功后引擎的位置不会移动,这样就能在同一位置继续寻找其他匹配项。

针对你的需求,可以修改正则为:

// 使用正向预查捕获重叠内容,同时过滤空匹配
const re = /(?=( .* ))|ba/g;
const matches = [...("foo bar baz".matchAll(re))].filter(m => m[0] !== "");
// 处理并输出匹配结果
console.log(`"foo bar baz".matchAll(/${re.source}/${re.flags}) = [`);
matches.map(matchProperties).forEach(props => console.log("	", props));
console.log("];");

这个正则的逻辑是:

  • (?=( .* )):正向预查匹配" bar ",但不消耗字符,匹配后位置仍停在索引3;
  • ba:接着可以匹配到索引4的"ba",之后位置移动到6,继续往后匹配到索引8的"ba";
  • 最后过滤掉空匹配(因为正向预查本身不会生成匹配内容,需要从捕获组提取或调整正则避免空匹配)。

总结

  • 默认正则匹配是非重叠的,这是所有正则引擎的通用行为;
  • matchAll只是按照正则引擎的结果返回匹配项,本身不会改变匹配逻辑;
  • 要实现重叠匹配,必须通过零宽度断言等技巧让引擎不消耗字符,从而在同一位置继续查找。

内容的提问来源于stack exchange,提问作者Daniel Kaplan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 14:23:15