此问题特定于Java 7/8。
使用量词的相当复杂的正则表达式在这样的后观断言中是被禁止的:
(?<=(a|b*)*)bc
因为它会导致运行时异常,并带有如下消息:
look-behind group does not have obvious maximum length error
我猜这是因为*
和+
等量词通常是&#34;&#34;不允许。
但是,以下方法确实有效:
(?<=a*)bc
为什么会这样?
在SO上有关于此问题的类似帖子:
有些帖子是针对Java的,但似乎没有提供具体的答案或引用,例如this。大多数答案都说明这些量词根本无法使用。另外,regular-expressions网站也说明了相同的内容。
This post表示Java在实施方面存在缺陷。
但是,我在上面显示的使用lookbehind中的零或多个量词*
的示例对Java 7/8有效。
任何参考或解释都会有所帮助。
答案 0 :(得分:1)
在查看Pattern
代码并尝试跟踪它之后,我确信这只是一个错误。这两个例子都应该导致异常。但是测试这个的逻辑是不正确的。
此代码出现在几个地方:
temp = info.maxLength * cmax + maxL;
info.maxLength = temp;
if (temp < maxL) {
info.maxValid = false;
}
请注意,只要maxLength
和cmax
为非负,temp
就不应小于maxL
,除非发生溢出。最后一个代码使用maxValid
;如果maxValid
为false
,则会引发"look-behind group does not have obvious maximum length error"
。
据我所知,在&lt; prefix&gt; &lt; expression&gt; {m,n}
这样的正则表达式中,在上面的代码中{{1} }是&#34;表达式&#34;的最大长度,info.maxLength
是量词的上限,cmax
是&#34;前缀&#34;的最大长度。当量词为maxL
或*
时,上限设置为+
。 (此处的所有变量均为Integer.MAX_VALUE
。)这意味着除非int
为1且info.maxLength
为0 ,否则会出现溢出。
maxL
因为带有量词的模式的长度为1,并且(?<=a*)bc
之前没有任何内容,这意味着a*
将为0.这就是为什么这个案例会破裂的原因。
对于任何其他值,计算将溢出,但这并不意味着maxL
将成立。如果temp < maxL
是偶数,则会抛出异常;但是如果info.maxLength
是奇数,那么如果info.maxLength
足够小,模式就会编译。这是因为环绕式工作方式,数学上;尝试检查溢出的代码是非常错误的。这意味着
maxL
此外:
(?<=a*)bc // succeeds
(?<=(ab)*)bc // throws exception
(?<=(abc)*)bc // succeeds
(?<=(abcd)*)bc // throws exception
(?<=(abcde)*)bc // succeeds
注意:应该注意的是,在你的示例正则表达式中,lookbehind是无用的:
(?<=xa*)bc // throws exception
(?<=x(abc)*)bc // succeeds
lookbehind表示测试当前位置是否在字母(?<=a*)bc
出现零次或多次之前。这总是正确的,琐碎的。因此,后视在这里没有任何意义。类似地,
a
相当于
(?<=a+)bc
因为只要在当前位置之前有一个(?<=a)bc
,所以可能会有多少并不重要。所有不会抛出异常的例子都是如此,除了这个:
a
因为匹配器必须向后搜索字符串中的(?<=x(abc)*)bc // succeeds
并确保最后一个字符串前面有abc
。在这种情况下x
似乎应该抛出一个异常,但是由于错误的溢出检查逻辑,它不是。因此,我不确定它是否会实际返回正确的结果,或者它是否会崩溃或进入无限循环。但是,我还没试过。
实际上,代码应该直接检查Pattern
是否等于cmax
,而不是在计算中使用它,并希望代码稍后可以告诉结果是伪造的。