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

Posted

技术标签:

【中文标题】为啥在 regex char 可选时找不到匹配项【英文标题】:Why are no matches found when ever regex char optional为什么在 regex char 可选时找不到匹配项 【发布时间】:2016-02-19 08:59:04 【问题描述】:

我对为什么会发生这种情况感到非常困惑,并希望有人能解释正则表达式引擎中发生的事情的机制。

在进行代码战练习时,“您的意思是……?”在 javascript 中,我试图计算 word1 中有多少字符出现在 word2 中。我正在尝试将每个字符作为其自己的匹配组进行匹配,以便稍后我可以计算数组中成功匹配的数量,并使用它来找出这两个单词的相似程度。

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

我试过了:

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

没有找到匹配项

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

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

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

我尝试过的其他事情: - 樱桃匹配樱桃按我的预期工作

'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 上添加? 意味着我不再看到任何匹配的字符?

虽然我在 JS 中尝试过,但我在 PY 和 PCRE 中得到了相同的结果

【问题讨论】:

? 表示一个或无,并且总是为真 - 找不到任何内容被视为匹配项。它是贪婪的,因为它试图首先找到一些东西(而不是相反的惰性量词:尝试满足于nothing)。 您没有在 JS 中使用 /g,因此您得到了一个匹配项:字符串开头的空位置。看看this demo 感谢 Jan,Wiktor - 特别是 Wiktor - 这很有意义。因此,正则表达式引擎在尝试匹配的字符串上从左到右工作,如果没有 g 标志,它会在字符串的开头找到零字符的匹配。 【参考方案1】:

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

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

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

【讨论】:

以上是关于为啥在 regex char 可选时找不到匹配项的主要内容,如果未能解决你的问题,请参考以下文章

为啥会出现错误:在 truffle 上编译时找不到导入

为啥我的代码在渲染时找不到类?

为啥使用 Origin 标头时找不到路由

为啥使用 RDP 时找不到远程 SmartCard

Google Play Developer API - 为啥在用户执行重新订阅时找不到linkedPurchaseToken?

为啥我使用 setup.py 安装时找不到 ansible?