62

例如,下面的正则表达式会导致失败报告lookbehind assertion is not fixed length

#(?<!(?:(?:src)|(?:href))=["\']?)((?:https?|ftp)://[^\s\'"<>()]+)#S

对于前瞻,这种限制不存在。

4

5 回答 5

91

Lookahead 和lookbehind 并不像它们的名字所暗示的那样相似。前瞻表达式的工作方式与它是一个独立的正则表达式完全相同,除了它锚定在当前匹配位置并且它不消耗它匹配的内容。

向后看是一个完全不同的故事。从当前匹配位置开始,它一次一个字符地向后遍历文本,尝试在每个位置匹配其表达式。在无法匹配的情况下,后视必须一直到文本的开头(一次一个字符,记住),然后才会放弃。将其与只应用一次的前瞻表达式进行比较。

当然,这是一个严重的过度简化,并不是所有的口味都这样,但你明白了。应用lookbehinds 的方式与应用lookaheads 的方式根本不同(而且效率要低得多)只有限制后视必须向后看多远才有意义。

于 2010-09-26T09:54:50.890 回答
13

首先,并非所有正则表达式库(如 .NET)都如此。

对于 PCRE,原因似乎是:

对于每个备选方案,lookbehind 断言的实现是暂时将当前位置向后移动固定宽度,然后尝试匹配。

(至少,根据http://www.autoitscript.com/autoit3/pcrepattern.html)。

于 2010-09-26T03:41:14.263 回答
12

PCRE 不支持浮动后视,因为它会导致严重的性能问题。这是因为缺少从右到左的匹配能力:PCRE 只能从一个固定的左边开始一个分支,而一个可变长度的lookbehind 的左边不能是固定的。

通常,如果可能,请尝试将您的后视部分分支到固定长度的模式。例如,而不是:

(?<=(src|href)=")etc.

(1)使用这个:

(?:(?<=src=")|(?<=href="))etc.

(2)或与\K

(src|href)="\Ketc.

请注意,这\K不是真正的后视,因为它总是在上一个匹配结束时开始搜索(没有潜在的后退到上一个匹配)。

(3)在某些复杂的lookbehind-only 情况下,您可以在反向字符串中使用“反向”lookahead 表达式进行搜索。不太优雅,但它有效:

.cte(?="=(ferh|crs))
于 2016-10-17T03:24:16.373 回答
5

我有同样的问题并通过使用修复它 (?: subexpression)

定义一个非捕获组。例如Write(?:Line)?“Console.WriteLine()”中的“WriteLine”“Console.Write(value)”中的“Write”

我必须更改下面的正则表达式,它应该在之前, 字符串的开头捕获,这给了我lookbehind assertion is not fixed length

(?<=,|^)

有了这个,

(?:(?<=,)|^)
于 2015-01-30T00:47:56.580 回答
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

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

于 2017-12-10T23:32:08.793 回答