在一个源代码中,我发现了这个正则表达式:
qr/(?!)/;
我根本无法弄清楚这匹配什么。
老实说,绝对不明白A 零宽度负前瞻断言是什么意思。- 我在 perlre 中找到的。:(
有人可以用人类语言解释一下吗?:)
空的正则表达式模式匹配一个零长度的字符串,也就是说它总是匹配的。这是一个明显的进步:
'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 a
s,所以ab
不匹配,所以引擎回溯。第二次通过,a*
只匹配 3 个a
,从而允许ab
整个模式匹配。
我最初给出的示例的分步流程如下:
(.+?)
a
在 pos 0匹配(?{ print "$1\n" })
打印a
并匹配零个字符(?!)
不匹配。⇒ 回溯!(.+?)
ab
在 pos 0匹配(?{ print "$1\n" })
打印ab
并匹配零个字符(?!)
不匹配。⇒ 回溯!(.+?)
abc
在 pos 0匹配(?{ print "$1\n" })
打印abc
并匹配零个字符(?!)
不匹配。⇒ 回溯!(.+?)
abcd
在 pos 0匹配(?{ print "$1\n" })
打印abcd
并匹配零个字符(?!)
不匹配。⇒ 回溯!(.+?)
在这里无法匹配其他任何东西。⇒ 回溯!(.+?)
b
在 pos 1匹配(?{ print "$1\n" })
打印b
并匹配零个字符(?!)
不匹配。⇒ 回溯!(.+?)
d
在 pos 3匹配(?{ print "$1\n" })
打印d
并匹配零个字符(?!)
不匹配。⇒ 回溯!(.+?)
在这里无法匹配其他任何东西。⇒ 回溯!(.+?)
不匹配。⇒ 回溯!这是合法的,但根本不匹配。
该(?!...)
构造是一个否定的前瞻断言。详细地说,它的意思是:“匹配 ( ...
) 后面的正则表达式不应匹配输入字符串的位置”。
但在这种情况下,“后面的正则表达式”是空的正则表达式,它匹配所有内容。
所以,这个正则表达式本质上是说“匹配一个空正则表达式不能匹配的位置”......并且无论输入字符串如何,都不可能有这样的位置。这是一个总是失败的正则表达式结构!
(?=)
,一个空的正向前瞻,将始终匹配。这是设置最后一次成功匹配的值的一种骇人听闻的方式。(?!)
是它的倒数,并且永远不会匹配。