【问题标题】:How to get all possible overlapping matches for a string如何获取字符串的所有可能重叠匹配
【发布时间】:2013-08-03 05:08:09
【问题描述】:

我正在研究“哥德尔、埃舍尔、巴赫”第 2 章中的 MIU 系统问题。

规则状态之一

Rule III: If III occurs in one of the strings in your collection, you may make a new string with U in place of III.

这意味着字符串MIII可以变成MU,但是对于其他更长的字符串可能有多种可能性[括号中的匹配项]:

  • MIIII 可以产生
    • M[III]I >> MUI
    • MI[III] >> MIU
  • MUIIIUIIIU 可以产生
    • MU[III]UIIIU >> MUUUIIIU
    • MUIIIU[III]U >> MUIIIUUU
  • MUIIIIU 可以产生
    • MU[III]IU >> MUUIU
    • MUI[III]U >> MUIUU

/(.*)III(.*)/ 之类的正则表达式显然很有帮助,但我似乎无法让它们生成所有可能的匹配项,只生成它碰巧找到的第一个匹配项。

有没有办法生成所有可能的匹配项?

(请注意,我可以想办法完全手动执行此操作,但我希望有更好的方法使用内置工具、正则表达式或其他方式)

(已编辑以阐明重叠的需求。)

【问题讨论】:

  • 您是否在问如何在字符串中的任何位置获取所有出现的 III,包括重叠匹配,并将它们返回到数组中?
  • 是的,根据示例。例如MIIII 应该有两个匹配项,用于 M[III]I 和 MI[III]。 (这些继续成为 MUI 和 MIU)。 Exec 看起来很有希望,但它不会处理重叠的情况。
  • RegExp.exec 可以为您工作,但您需要使用匹配对象,如 Kolink 的回答所示。在这种情况下,indexOf 可能更好,但正则表达式肯定更通用。
  • 霍夫施塔特也在俄勒冈度过了一段时间,不是吗?

标签: javascript regex


【解决方案1】:

这是您需要的正则表达式:/III/g - 够简单吧?现在看看你如何使用它:

var text = "MUIIIUIIIU", find = "III", replace "U",
    regex = new RegExp(find,"g"), matches = [], match;
while(match = regex.exec(text)) {
    matches.push(match);
    regex.lastIndex = match.index+1;
}

regex.lastIndex... 行覆盖了通常的正则表达式行为,即不匹配过度的结果。此外,我正在使用 RegExp 构造函数来使其更加灵活。您甚至可以通过这种方式将其构建到函数中。

现在你有了一个匹配对象数组,你可以这样做:

matches.forEach(function(m) { // older browsers need a shim or old-fashioned for loop
    console.log(text.substr(0,m.index)+replace+text.substr(m.index+find.length));
});

编辑: Here 是演示上述代码的 JSFiddle。

【讨论】:

  • Hrm,为什么是+1,而不是-1?这似乎并没有解决我的问题,我仍然在戳它。我会报告我的发现。
  • 我不确定您为什么认为-1 会起作用。您需要在字符串中移动 forward,而不是向后移动。向后移动会反复找到完全相同的匹配并给你一个无限循环。在答案中编辑了一个 JSFiddle 链接。
  • 上面看错了,我直接编辑最后一个索引,结果发现用处不大。这似乎有效,非常感谢!
  • 很好,谷歌搜索了如何在 JavaScript 中进行正则表达式搜索以解决重叠匹配问题。大概找了 30 分钟,直到我用简单的regex.lastIndex = match.index + 1 解决方案找到了这篇文章。谢谢!
【解决方案2】:

有时正则表达式是多余的。在你的情况下,一个简单的indexOf 也可以!

诚然,这是一个 hack,但您可以自己将其转换为漂亮、可重用的代码:

var s = "MIIIIIUIUIIIUUIIUIIIIIU";
var results = [];
for (var i = 0; true; i += 1) {
    i = s.indexOf("III", i);
    if (i === -1) {
        break;
    }
    results.push(i);
}
console.log("Match positions: " + JSON.stringify(results));

它可以很好地处理重叠,至少在我看来,indexOf 看起来更简单。

【讨论】:

  • 是的,这个案例相当简单。它们变得有点复杂,理想情况下它基本上是开放式的。
  • 同意。你会想要更强大的 Mx → Mxx 规则:)
  • 是的,幸运的是正则表达式很好地处理了 Mx -> Mxx 情况:newTheorems.push( startingTheorem.replace( /(M)(.+)/i, "$1$2$2" ) );
  • Aaaaccc实际上,比这更容易:function Rule2(s) {return s + s.substring(1);},因为在 MIU 拼图中,所有字符串都以 M!
  • 不错,很好地使用了内置工具。不过,这有助于我学习 javascript 正则表达式。我已经知道 C ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-29
  • 2021-10-04
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 2015-05-13
相关资源
最近更新 更多