例如,下面的正则表达式会导致失败报告lookbehind assertion is not fixed length:
#(?<!(?:(?:src)|(?:href))=["\']?)((?:https?|ftp)://[^\s\'"<>()]+)#S
对于前瞻,这种限制不存在。
例如,下面的正则表达式会导致失败报告lookbehind assertion is not fixed length:
#(?<!(?:(?:src)|(?:href))=["\']?)((?:https?|ftp)://[^\s\'"<>()]+)#S
对于前瞻,这种限制不存在。
Lookahead 和lookbehind 并不像它们的名字所暗示的那样相似。前瞻表达式的工作方式与它是一个独立的正则表达式完全相同,除了它锚定在当前匹配位置并且它不消耗它匹配的内容。
向后看是一个完全不同的故事。从当前匹配位置开始,它一次一个字符地向后遍历文本,尝试在每个位置匹配其表达式。在无法匹配的情况下,后视必须一直到文本的开头(一次一个字符,记住),然后才会放弃。将其与只应用一次的前瞻表达式进行比较。
当然,这是一个严重的过度简化,并不是所有的口味都这样,但你明白了。应用lookbehinds 的方式与应用lookaheads 的方式根本不同(而且效率要低得多)。只有限制后视必须向后看多远才有意义。
首先,并非所有正则表达式库(如 .NET)都如此。
对于 PCRE,原因似乎是:
对于每个备选方案,lookbehind 断言的实现是暂时将当前位置向后移动固定宽度,然后尝试匹配。
(至少,根据http://www.autoitscript.com/autoit3/pcrepattern.html)。
PCRE 不支持浮动后视,因为它会导致严重的性能问题。这是因为缺少从右到左的匹配能力:PCRE 只能从一个固定的左边开始一个分支,而一个可变长度的lookbehind 的左边不能是固定的。
通常,如果可能,请尝试将您的后视部分分支到固定长度的模式。例如,而不是:
(?<=(src|href)=")etc.
(1)使用这个:
(?:(?<=src=")|(?<=href="))etc.
(2)或与\K
:
(src|href)="\Ketc.
请注意,这\K
不是真正的后视,因为它总是在上一个匹配结束时开始搜索(没有潜在的后退到上一个匹配)。
(3)在某些复杂的lookbehind-only 情况下,您可以在反向字符串中使用“反向”lookahead 表达式进行搜索。不太优雅,但它有效:
.cte(?="=(ferh|crs))
我有同样的问题并通过使用修复它 (?: subexpression)
定义一个非捕获组。例如
Write(?:Line)?
“Console.WriteLine()”中的“WriteLine”“Console.Write(value)”中的“Write”
我必须更改下面的正则表达式,它应该在之前,
或字符串的开头捕获,这给了我lookbehind assertion is not fixed length。
(?<=,|^)
有了这个,
(?:(?<=,)|^)
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
For processing efficiency PCRE does not support right-to-left matching or recursion. When doing a lookbehind PCRE searches the end of any previous matching string - implementing variable size matches would require recursion and reduce efficiency. See: Look Behind Assertions