为什么在 regex char 可选时找不到匹配项

Why are no matches found when ever regex char optional

我很困惑为什么会这样,希望有人能解释正则表达式引擎中发生的事情的机制。

在 Javascript 中进行 codewars 练习 "Did you mean...?" 时,我试图计算 word1 中有多少字符出现在 word2 中。我正在尝试将每个字符作为其自己的匹配组进行匹配,以便稍后我可以计算数组中成功匹配的数量,并使用它来找出这两个词的相似程度。

请不要给我提示如何解决 codewars 挑战,只是帮助我理解这里发生了什么。

我试过了:

'berry'.match(/(c?)(h?)(e?)(r?)(r?)(y?)/)

没有找到匹配项

> ["", "", "", "", "", "", ""]

这对我来说是个谜。搜索 Regular-expressions.info 后,?(使前面的字符可选)是贪婪的,所以虽然没有匹配对正则表达式有效,但它不应该首先被贪婪版本打败吗?我期待这个:

> ["", "", "", "e", "r", "r", "y"]

我尝试过的其他事情: - cherry match cherry 工作正常

'cherry'.match(/(c?)(h?)(e?)(r?)(r?)(y?)/)
> ["cherry", "c", "h", "e", "r", "r", "y"]

cherl match cherry 的效果也如我所料

'cherl'.match(/(c?)(h?)(e?)(r?)(r?)(y?)/)
> ["cher", "c", "h", "e", "r", "", ""]

如果我从最后的 y 中删除 ?,它也会按预期工作:

'berry'.match(/(c?)(h?)(e?)(r?)(r?)(y)/)
> ["erry", "", "", "e", "r", "r", "y"]

那么为什么在最后的 y 上添加 ? 意味着我不再看到任何匹配的字符?

虽然我已经在 J​​S 中尝试过,但我在 PY 和 PCRE 中得到了相同的结果

So why does adding a ? onto the final y mean I no longer see any matched characters?

您在开头使用的模式 - /(c?)(h?)(e?)(r?)(r?)(y?)/ - 可以匹配空字符串 因为所有子模式都是可选的(即可以匹配零次出现)。当您只查找一个匹配项时(例如 JavaScript 中的 String#match),您将始终获得位于字符串开头的匹配项(因为在大多数情况下,正则表达式引擎会分析从左到右的字符串),要么是空字符串(如果第一个字符无法与第一个子模式匹配),要么是某个子字符串(如果前导或所有子模式匹配)。

因此,berryb 开头。 /(c?)(h?)(e?)(r?)(r?)(y?)/ 以可选的 c 开头,因此,b 无法与 c 匹配,因此失败。 b 不能与 her、另一个 ry 匹配。请注意,如果将最后一个 y? 更改为 b?,则 will get a b in the match.

如果您不在 JS 正则表达式中使用 /g(全局)标志,引擎将只检查一个匹配项。它会在开头找到它 - 一个空字符串,return 它并收工。 If you use /g,它会检查所有位置,第二个匹配会给你你想要的结果。但是,当您将 String#match() 与基于 /g 的正则表达式一起使用时,您将丢失捕获的子字符串。使用 RegExp#exec() 可以访问这些子匹配项。

请注意,/(c?)(h?)(e?)(r?)(r?)(y)/ 为您提供了一个匹配项,因为最后一个 yobligatory,并且该模式不能再匹配空字符串。因此,当引擎在 berry 中看到 b 时,它匹配失败,继续检查 e 之前的下一个位置,并在那里找到匹配项。因此,在这种情况下不需要 /g