2

我有一些正则表达式的经验,但已经有一段时间了。我写了一个复杂的表达式,试图匹配我认为无效的产品代码中的某些模式。我在数千个代码上运行了我的代码来验证它,并且我发现了一些行为不符合预期的案例。

我已将其缩小到一个特定的问题,我在下面以简化的方式介绍了这个问题 - 这是我不理解的概念,而不是我正在使用的实际表达方式。我想找到以某种方式开始的代码,中间包含可选组件(但如果它们确实存在,它们必须完全匹配某个模式 - 我不能贪婪地匹配任何东西),但没有正确结束(应该以“d”结尾,但不要)。顺便说一句,它是通过 Windows 脚本主机在(gag)VBScript 中实现的。

^a(b)?(c)?(?!d$)

应该匹配的东西:

  • ae
  • 阿部
  • 高手
  • abce

不应该匹配的东西:

  • 广告
  • abd
  • acd
  • A B C D
  • 咖啡馆
  • 上一页
  • acfe
  • abcfe

本质上,“ae”匹配正确,但任何时候一个或两个选项应该匹配,它都会导致整个匹配失败。我认为这与贪婪的本性有关?但一直无法弄清楚如何让它发挥作用。同样,我不能使用类似下面的东西 - 如果组件存在于“a”和“e”之间,它们必须完全是“b”或“c”。

^a(?!.*d$)

谢谢!

4

1 回答 1

7

我假设“失败”是指abd不应该匹配的匹配。首先,让我们看看为什么会这样:

  1. a火柴a
  2. b火柴(b)?
  3. d不匹配(c)?,但是好的,它是可选的
  4. (?!d$)失败是因为我们就d在字符串的末尾。所以这种方法行不通。现在的问题是正则表达式引擎还没有尝试过另一种可能性,因此它会回溯到之前的位置b
  5. 让我们尽量不要使用(b)?匹配b,因为它是可选的。
  6. b也不匹配(c)?。好的,这是可选的。
  7. (?!d)成功是因为我们就cd在字符串末尾之前,并且不匹配d$. 成功!

所以,你可以做什么?如果您可以使用否定的lookbehind assertion那就太好了,但可惜的是,ECMAScript 正则表达式不支持这一点。

下一个最好的方法是将负前瞻放在正则表达式的开头:

^(?!.*d$)a(b)?(c)?

首先确保字符串不以d. 只有这样它才开始实际的比赛。现在这通过了你所有的测试用例。

于 2013-10-22T05:20:20.217 回答