例如,下面的正则表达式将导致失败报告 lookbehind断言不是固定长度:
#(?<!(?:(?:src)|(?:href))=["\']?)((?:https?|ftp)://[^\s\'"<>()]+)#S
lookahead
不存在此类限制。
答案 0 :(得分:63)
Lookahead和lookbehind并不像他们的名字所暗示的那样相似。前瞻表达式与它是一个独立的正则表达式完全相同,除了它锚定在当前匹配位置并且它不消耗它匹配的内容。
Lookbehind是一个完全不同的故事。从当前匹配位置开始,它一次向后翻阅文本一个字符,尝试在每个位置匹配其表达式。在不可能匹配的情况下,在它放弃之前,lookbehind必须一直到文本的开头(一次一个字符,记住)。将它与前瞻表达式进行比较,前瞻表达式只应用一次。
当然,这是一个粗略的过度简化,并不是所有的口味都是这样,但你明白了。应用lookbehinds的方式与前瞻应用方式的根本不同(并且很多,很多效率低)。限制后视镜的外观是有意义的。
答案 1 :(得分:9)
首先,对于所有正则表达式库(如.NET),情况并非如此。
对于PCRE,原因似乎是:
lookbehind的实现 断言是,对于每个替代方案, 暂时移动当前 按固定宽度向后定位 然后尝试匹配。
答案 2 :(得分:5)
PCRE不支持浮动后备,因为它可能会导致严重的性能问题。这是因为缺乏从右到左的匹配能力:PCRE只能从固定的左边开始分支,但是可变长度的后视左边不能修复。
通常,如果可能,尝试将lookbehind部分分支到固定长度模式。例如,而不是:
(?<=(src|href)=")etc.
(1)使用此:
(?:(?<=src=")|(?<=href="))etc.
(2)或\K
:
(src|href)="\Ketc.
请注意\K
不是真正的后视,因为它始终在上一场比赛结束时开始搜索(没有潜在的后退到前一场比赛)。
(3)在一些复杂的仅后视案例中,您可以使用反向字符串中的“倒置”前瞻表达式进行搜索。不太优雅,但它有效:
.cte(?="=(ferh|crs))
答案 3 :(得分:2)
我遇到了同样的问题,并使用(?: subexpression)
定义非捕获组。例如
Write(?:Line)?
&#34; WriteLine&#34;在 &#34; Console.WriteLine()&#34; &#34;写&#34;在&#34; Console.Write(值)&#34;
我必须更改下面的正则表达式,假设在,
之前捕获或字符串开头的东西,这给了我 lookbehind断言不是固定长度强>
(?<=,|^)
有了这个,
(?:(?<=,)|^)
答案 4 :(得分:0)
grep -P '(?<=((three)|(one)) )two' <<< "one two three three two one"
grep: lookbehind assertion is not fixed length
grep -P '((?<=(three) )|(?<=(one) ))two' <<< "one two three three two one"
one two three three two one