【问题标题】:Regex why does negative lookahead not work when there are two groups here当这里有两组时,正则表达式为什么负前瞻不起作用
【发布时间】:2013-10-16 02:13:12
【问题描述】:

当我尝试这个正则表达式时

\"(\S\S+)\"(?!;c)

在这个字符串 "MM:";d 上它是我想要的匹配

在这个字符串 "MM:";c 上,它与期望的不匹配。

但是当我添加第二个组时,通过在该组内移动分号并使用 | 使其成为可选

\"(\S\S+)\"(;|)(?!c)

对于这个字符串 "MM:";c,它与我之前预期的不一样。

我在 Java 上尝试过这个,然后在 Javascript 上使用 Regex 工具 debuggex:

This link contains a snippet of the above

我做错了什么?

注意 |所以没有必要有分号。同样在示例中我放了 c,它只是示例中单词的替代品,这就是我使用否定前瞻的原因。

在遵循 Holgers 对使用所有格量词的反应后,

\"(\S\S+)\";?+(?!c)

成功了,here is a link to it on RegexPlanet

【问题讨论】:

  • 您似乎有“半个 OR 语句”(;|)there - 这是故意的吗?对我来说,这似乎意味着“要么是分号,要么什么都没有”。所以匹配是正确的?
  • 我用它来使分号可选
  • 最好使用问号:;?。这意味着完全相同的东西,但它增加了更少的混乱,并且你会得到更少的 cmets 询问这是否是你真正的意思。 ;)
  • 有什么理由不简单地使用^"(\S+)";?[^c]$
  • 这是我在调试后想出的简化版本,以找出导致错误的原因。我需要将分号作为一个组捕获,因为我将在实际代码中对其进行扩展。

标签: java javascript regex negative-lookahead


【解决方案1】:

我相信正则表达式会尽其所能找到匹配项;由于您的表达式说分号可以是可选的,因此它发现它可以匹配整个表达式(因为如果第一组没有使用分号,它就成为否定前瞻的“不匹配”。这与正则表达式工作的递归方式:它一直试图找到一个匹配...

换句话说,过程是这样的:

MM:" - matched
(;|) - try semicolon? matched
(?!c) - oops - negative lookahead fails. No match. Go back
(;|)  - try nothing. We still have ';c' left to match
(?!c) - negative lookahead not matched. We have a match 

更新(基于您的评论)。以下代码可能会更好:

\"(\S\S+)\"(;|)((?!c)|(?!;c))

Debuggex Demo

【讨论】:

  • 当我打印出分号有时出现在第 2 组中的组时,它似乎正在消耗第二组中的分号,就像在 Java 中一样
  • 如果这样做会导致完全匹配,它将消耗分号。但如果这意味着随后会触发负前瞻,它就不会这样做。所以MM:";d 将捕获第二组中的分号(贪婪),但MM:";c 不会(因为如果分号已被消耗,它将导致前瞻条件失败)。这与观察到的行为相符吗?
  • 是的,似乎是这样。有没有办法强制它消耗第二组中的分号,同时保持它是可选的
  • 你可以试试 (;)?[^c;]
  • 问题是我在这个例子中用 C 代替了一个词,以使其更简单,但这就是我使用否定前瞻的原因
【解决方案2】:

问题是你不想让分号在正则表达式的意义上是可选的。可选分号表示允许匹配器尝试两者,匹配或不匹配。因此,即使有分号,匹配器也可以忽略它,为组创建一个空匹配,让前瞻成功。

但是如果分号在那里,你想消费它,所以它不允许用于满足负前瞻。使用 Java 的正则表达式引擎非常简单:使用 ;?+

这被称为“占有量词”。与? 一样,分号不需要存在,但 if 存在它必须匹配且不能忽略。所以正则表达式引擎已经别无选择了。

因此,如果您需要分组中的分号,则整个模式看起来像 \"(\S\S+)\";?+(?!c)\"(\S\S+)\"(;?+)(?!c)

【讨论】:

  • 但我需要分号是可选的,问题就在这里,因为我没有意识到正则表达式会做任何事情来获得匹配。我现在已经删除了否定的lookahead并使其成为一个组,然后在匹配后,我检查匹配的组以查看c字是否存在
  • 请尝试理解:使用所有格量词,分号 可选的,但正则表达式不再允许“为匹配而做任何事情”。这正是您想要的(或者至少是您所描述的)
  • 当我将你的公式插入到 Debuggex Demo 中时,它就像“没有什么可重复的”。
  • 好吧,我提到了 Java 的正则表达式引擎,因为您的问题被标记为 Java。并非每个引擎都支持占有量词。
  • JavaScript 中,您可以使用前瞻和后向引用来模拟占有量词(或原子组):(?=(;?))\1 等同于;?+,但您必须注意适应后面- 在该术语之前引入更多组时的参考。
猜你喜欢
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 2017-04-22
  • 2014-12-20
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
  • 1970-01-01
相关资源
最近更新 更多