在一个源代码中,我找到了这个正则表达式:
qr/(?!)/;
我根本无法弄清楚这匹配的是什么。
老实说,绝对不明白什么意味着零宽度负面前瞻断言。 - 我在perlre中找到的东西。 :(
有人可以用人类语言解释吗? :)
答案 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
,从而匹配整个模式。
我最初给出的示例的分步流程如下:
(.+?)
匹配位置0 a
(?{ print "$1\n" })
打印a
并匹配零字符(?!)
不匹配。 ⇒回溯!(.+?)
匹配位置0 ab
(?{ print "$1\n" })
打印ab
并匹配零字符(?!)
不匹配。 ⇒回溯!(.+?)
匹配位置0 abc
(?{ print "$1\n" })
打印abc
并匹配零字符(?!)
不匹配。 ⇒回溯!(.+?)
匹配位置0 abcd
(?{ print "$1\n" })
打印abcd
并匹配零字符(?!)
不匹配。 ⇒回溯!(.+?)
无法与此处的任何其他内容匹配。 ⇒回溯!(.+?)
匹配位置1 b
(?{ print "$1\n" })
打印b
并匹配零字符(?!)
不匹配。 ⇒回溯!(.+?)
匹配位置3 d
(?{ print "$1\n" })
打印d
并匹配零字符(?!)
不匹配。 ⇒回溯!(.+?)
无法与此处的任何其他内容匹配。 ⇒回溯!(.+?)
不匹配。 ⇒回溯!答案 1 :(得分:14)
这是合法的,但根本不匹配。
(?!...)
构造是否定先行断言。具体来说,它意味着:“匹配后面的正则表达式(...
)应该不匹配输入字符串的位置”。
但在这种情况下,“后面的正则表达式”是空的正则表达式,它匹配所有内容。
所以,这个正则表达式实质上是说“匹配一个位置,其中后面的内容无法与空正则表达式相匹配”......并且无论输入字符串如何,都不会有这样的位置。这是一个总是失败的正则表达式构造!
答案 2 :(得分:1)
(?=)
,一个空的正面前瞻,将始终匹配。设置上次成功比赛的价值是一种骇人的方式。 (?!)
是反向的,永远不会匹配。