在一个源代码中,我发现了这个正则表达式:
qr/(?!)/;
Run Code Online (Sandbox Code Playgroud)
我根本无法弄清楚这匹配的是什么.
老实说,绝对不明白什么意味着A零宽度负前瞻断言. - 我在perlre中找到了什么.:(
有人可以用人类语言解释吗?:)
ike*_*ami 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)
Run Code Online (Sandbox Code Playgroud)
这意味着(?=)("这个位置后跟一个零长度的字符串吗?")总是匹配和(?!)("这个位置后面没跟一个零长度的字符串?")从不匹配.事实上,自从后者在5.10中的引入以来,(?!)已经过优化(*FAIL).
(?!)(*FAIL)当模式具有副作用时,aka 也可用于强制回溯.
'abcd' =~ /(.+?)(?{ print "$1\n" })(?!)/;
Run Code Online (Sandbox Code Playgroud)
输出:
a
ab
abc
abcd
b
bc
bcd
c
cd
d
Run Code Online (Sandbox Code Playgroud)
示例说明:
(?!)不匹配,所以正则表达式引擎一直试图通过.+?匹配越来越多的字符来找到匹配.当失败时,正则表达式引擎会尝试在稍后的起始位置进行匹配.
这被称为"回溯".这是正则表达式引擎可以匹配的方式'aaaab' =~ /a*ab/.第一次通过,a*匹配所有4 a秒,所以ab不匹配,所以引擎回溯.第二次通过,a*只匹配as 中的3个,允许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并匹配零字符(?!)不匹配.⇒回溯!(.+?)在这里无法匹敌.⇒回溯!(.+?)在比赛b1 比赛(?{ print "$1\n" })打印b并匹配零字符(?!)不匹配.⇒回溯!(.+?)比赛d在pos 3(?{ print "$1\n" })打印d并匹配零字符(?!)不匹配.⇒回溯!(.+?)在这里无法匹敌.⇒回溯!(.+?)不匹配.⇒回溯!fge*_*fge 14
这是合法的,但根本不匹配.
该(?!...)构造是一个负面的先行断言.详细地说,它意味着:"匹配后面的正则表达式(...)与输入字符串不匹配的位置".
但在这种情况下,"后面的正则表达式"是空的正则表达式,它匹配所有东西.
因此,这个正则表达式实质上是说"匹配一个位置,其中后面的内容无法与空正则表达式相匹配"......并且无论输入字符串如何,都不会有这样的位置.这是一个总是失败的正则表达式构造!