什么匹配这个正则表达式:qr /(?!)/;

时间:2013-06-01 00:11:55

标签: regex perl

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

qr/(?!)/;

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

老实说,绝对不明白什么意味着零宽度负面前瞻断言。 - 我在perlre中找到的东西。 :(

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

3 个答案:

答案 0 :(得分: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)

这意味着(?=)(“这个位置后跟一个零长度的字符串?”)总是匹配并且(?!)(“这个位置后面跟不是零长度字符串吗?”)从不匹配。实际上,(?!)已经优化为(*FAIL),因为后者在5.10中被引入。

当模式有副作用时,

(?!) aka (*FAIL)对于强制回溯非常有用。

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

输出:

a
ab
abc
abcd
b
bc
bcd
c
cd
d

示例说明:

(?!)不匹配,因此正则表达式引擎会通过.+?匹配越来越多的字符来继续尝试查找匹配项。当失败时,正则表达式引擎会尝试在稍后的起始位置匹配。

这称为“回溯”。这是正则表达式引擎与'aaaab' =~ /a*ab/匹配的方式。第一次,a*匹配所有4个a,因此ab不匹配,因此引擎回溯。第二次,a*仅匹配a中的3个,允许ab,从而匹配整个模式。

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

  1. 在pos 0开始匹配。
  2. (.+?)匹配位置0
  3. a
  4. (?{ print "$1\n" })打印a并匹配零字符
  5. (?!)不匹配。 ⇒回溯!
  6. (.+?)匹配位置0
  7. ab
  8. (?{ print "$1\n" })打印ab并匹配零字符
  9. (?!)不匹配。 ⇒回溯!
  10. (.+?)匹配位置0
  11. abc
  12. (?{ print "$1\n" })打印abc并匹配零字符
  13. (?!)不匹配。 ⇒回溯!
  14. (.+?)匹配位置0
  15. abcd
  16. (?{ print "$1\n" })打印abcd并匹配零字符
  17. (?!)不匹配。 ⇒回溯!
  18. (.+?)无法与此处的任何其他内容匹配。 ⇒回溯!
  19. 在pos 1开始匹配。
  20. (.+?)匹配位置1
  21. b
  22. (?{ print "$1\n" })打印b并匹配零字符
  23. (?!)不匹配。 ⇒回溯!
  24. ...
  25. (.+?)匹配位置3
  26. d
  27. (?{ print "$1\n" })打印d并匹配零字符
  28. (?!)不匹配。 ⇒回溯!
  29. (.+?)无法与此处的任何其他内容匹配。 ⇒回溯!
  30. 在pos 4开始匹配。
  31. (.+?)不匹配。 ⇒回溯!
  32. 图案不匹配。

答案 1 :(得分:14)

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

(?!...)构造是否定先行断言。具体来说,它意味着:“匹配后面的正则表达式(...)应该匹配输入字符串的位置”。

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

所以,这个正则表达式实质上是说“匹配一个位置,其中后面的内容无法与空正则表达式相匹配”......并且无论输入字符串如何,都不会有这样的位置。这是一个总是失败的正则表达式构造!

答案 2 :(得分:1)

(?=),一个空的正面前瞻,将始终匹配。设置上次成功比赛的价值是一种骇人的方式。 (?!)是反向的,永远不会匹配。