7

在 Javascript 中,我有一个字符串abcdef,无法弄清楚这种奇怪的行为:

  • (?=abc)def与字符串不匹配
  • abc(?=def)匹配字符串

为什么?

4

4 回答 4

19

在捕获(?=abc)def(?=abc)宽度为零,并且在成功匹配后不会在输入字符串中向前移动光标。该构造只是说向前看接下来的三个字符,看看它们是否是abc,如果它们是,然后检查这些相同的字符是否是 def。此时匹配失败..

您需要了解正则表达式引擎如何工作以完成您的匹配。考虑您的输入字符串abcdef和您的正则表达式abc(?=def)。引擎首先匹配 ,a然后将输入字符串中的光标移动到下一个字符并尝试匹配 ,b因为输入字符串中的光标在b匹配成功。然后引擎将光标移到输入字符串中并尝试匹配c,因为光标在输入字符串中,c所以匹配成功并且输入字符串中的光标再次移动到下一个字符。现在引擎在这一点上遇到(?=def)引擎只是向前看,看看光标在输入字符串中的下三个字符是否实际上是def不移动光标,它们就是这样,匹配成功完成。

现在考虑输入字符串xyz和一个正则表达式x(?=y)Z。正则表达式引擎将光标放在输入字符串中的第一个字母上并检查它是否为 anx并找到它,x因此它将光标移动到输入字符串中的下一个字符。现在它向前看,看下一个字符是否是 a y,它是,但引擎不会移动输入文本光标前言,因此输入文本中的光标停留在y. 接下来引擎查看光标是否在字母上z,但由于输入文本中的光标仍在字母y上,匹配失败。

您可以在http://www.regular-expressions.info/lookaround.html阅读更多关于正面和负面预测的 信息

于 2013-06-10T01:23:22.947 回答
4

(?=...)是一个前瞻,换句话说,它测试它右边的字符串。还要注意,前瞻是不吃字符的零宽度断言。在您的第一个示例中:(?=abc)这意味着必须紧随abc其后def。这就是模式失败的原因。

在您的第二个示例中,它找到defafter abc,然后匹配字符串

于 2013-06-10T01:26:49.797 回答
2

根据您对我的评论的回复,我认为您想要的是积极的回顾

(?<=abc)def

编辑:

既然您使用的是 JavaScript(抱歉,我只阅读了您的问题——我没有查看标签),为什么不直接使用常规捕获组并将匹配项包含在替换模式中呢?

"abcdef".replace(/(abc)def/, "$1")
于 2013-06-10T01:37:56.270 回答
2

MDN在 JavaScript中对前瞻的定义

x(?=y)
仅当 'x' 后跟 'y' 时才匹配 'x'。这称为前瞻。

例如,/Jack(?=Sprat)/仅当 'Jack' 后跟 'Sprat' 时才匹配。/Jack(?=Sprat|Frost)/仅当它后面跟着 'Sprat' 或 'Frost' 时才匹配 'Jack'。但是,“Sprat”和“Frost”都不是比赛结果的一部分。

所以(?=y)前面有另一个语句,在这种情况下是一个空字符串,那么只有当第一个语句后面跟着第二个语句时它才会匹配。如果没有前导语句,表达式(?="abc")将匹配前 3 个字符 abc 而不捕获它们,然后再次检查这些字符是否为 def,这将失败。

于 2013-06-10T01:23:41.063 回答