13

在一个源代码中,我发现了这个正则表达式:

qr/(?!)/;

我根本无法弄清楚这匹配什么。

老实说,绝对不明白A 零宽度负前瞻断言是什么意思。- 我在 perlre 中找到的。:(

有人可以用人类语言解释一下吗?:)

4

3 回答 3

25

空的正则表达式模式匹配一​​个零长度的字符串,也就是说它总是匹配的。这是一个明显的进步:

'bbbbb' =~ /^(?:aaa|bbb)/   # Matches (Matches 3 "b"s, from pos 0 to 3)
'bbbbb' =~ /^(?:aaa|bb)/    # Matches (Matches 2 "b"s, from pos 0 to 2)
'bbbbb' =~ /^(?:aaa|b)/     # Matches (Matches 1 "b",  from pos 0 to 1)
'bbbbb' =~ /^(?:aaa|)/      # Matches (Matches 0 "b"s, from pos 0 to 0)

这意味着(?=)(“此位置后跟零长度字符串吗?”)始终匹配,而(?!)(“此位置后跟零长度字符串吗?”)从不匹配。事实上,自后者在 5.10 中引入以来已(?!)被优化。(*FAIL)

(?!)(*FAIL)当模式有副作用时,aka对强制回溯很有用。

'abcd' =~ /(.+?)(?{ print "$1\n" })(?!)/;

输出:

a
ab
abc
abcd
b
bc
bcd
c
cd
d

示例说明:

(?!)不匹配,因此正则表达式引擎不断尝试通过.+?匹配越来越多的字符来找到匹配项。如果失败,正则表达式引擎会尝试在稍后的起始位置进行匹配。

这称为“回溯”。这就是正则表达式引擎可以匹配的方式'aaaab' =~ /a*ab/。第一次通过,a*匹配所有 4 as,所以ab不匹配,所以引擎回溯。第二次通过,a*只匹配 3 个a,从而允许ab整个模式匹配。

我最初给出的示例的分步流程如下:

  1. 从 pos 0 开始匹配。
  2. (.+?)a在 pos 0匹配
  3. (?{ print "$1\n" })打印a并匹配零个字符
  4. (?!)不匹配。⇒ 回溯!
  5. (.+?)ab在 pos 0匹配
  6. (?{ print "$1\n" })打印ab并匹配零个字符
  7. (?!)不匹配。⇒ 回溯!
  8. (.+?)abc在 pos 0匹配
  9. (?{ print "$1\n" })打印abc并匹配零个字符
  10. (?!)不匹配。⇒ 回溯!
  11. (.+?)abcd在 pos 0匹配
  12. (?{ print "$1\n" })打印abcd并匹配零个字符
  13. (?!)不匹配。⇒ 回溯!
  14. (.+?)在这里无法匹配其他任何东西。⇒ 回溯!
  15. 从 pos 1 开始匹配。
  16. (.+?)b在 pos 1匹配
  17. (?{ print "$1\n" })打印b并匹配零个字符
  18. (?!)不匹配。⇒ 回溯!
  19. ...
  20. (.+?)d在 pos 3匹配
  21. (?{ print "$1\n" })打印d并匹配零个字符
  22. (?!)不匹配。⇒ 回溯!
  23. (.+?)在这里无法匹配其他任何东西。⇒ 回溯!
  24. 从位置 4 开始匹配。
  25. (.+?)不匹配。⇒ 回溯!
  26. 图案不匹配。
于 2013-06-01T00:22:05.340 回答
14

这是合法的,但根本不匹配。

(?!...)构造是一个否定的前瞻断言。详细地说,它的意思是:“匹配 ( ...) 后面的正则表达式不应匹配输入字符串的位置”。

但在这种情况下,“后面的正则表达式”是空的正则表达式,它匹配所有内容。

所以,这个正则表达式本质上是说“匹配一个空正则表达式不能匹配的位置”......并且无论输入字符串如何,都不可能有这样的位置。这是一个总是失败的正则表达式结构!

于 2013-06-01T00:22:08.730 回答
1

(?=),一个空的正向前瞻,将始终匹配。这是设置最后一次成功匹配的值的一种骇人听闻的方式。(?!)是它的倒数,并且永远不会匹配。

于 2013-06-01T00:20:33.610 回答