查看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"。
据我所知,在像 {m,n} 这样的正则表达式中,在上面的代码中,info.maxLength 是最大长度“表达式”,cmax是量词的上限,maxL是“前缀”的最大长度。当量词为* 或+ 时,上限设置为Integer.MAX_VALUE。 (这里所有的变量都是int。)这意味着会有溢出除非info.maxLength是1,maxL是0。这正是
(?<=a*)bc
因为带有量词的模式的长度为 1,而在 a* 之前没有任何内容,这意味着 maxL 将是 0。这就是为什么这种情况下落空的原因。
对于任何其他值,计算都会溢出,但这并不一定意味着temp < maxL 会为真。如果info.maxLength为偶数,则抛出异常;但是如果info.maxLength 是奇数,则如果maxL 足够小,则该模式将编译。这是因为在数学上环绕的工作方式;试图检查溢出的代码非常错误。这意味着
(?<=a*)bc // succeeds
(?<=(ab)*)bc // throws exception
(?<=(abc)*)bc // succeeds
(?<=(abcd)*)bc // throws exception
(?<=(abcde)*)bc // succeeds
还有:
(?<=xa*)bc // throws exception
(?<=x(abc)*)bc // succeeds
注意: 需要注意的是,在您的示例正则表达式中,lookbehind 是无用的:
(?<=a*)bc
lookbehind 表示测试当前位置之前是否有零次或多次出现的字母 a。这总是正确的,微不足道的。因此,后视在这里毫无用处。同样,
(?<=a+)bc
等价于
(?<=a)bc
只要在当前位置之前有一个a,可能还有多少并不重要。所有不抛出异常的示例都是如此,除了这个:
(?<=x(abc)*)bc // succeeds
因为这里匹配器必须向后查找字符串中的abc,并确保最后一个前面有x。在这种情况下,Pattern 似乎应该抛出异常,但由于溢出检查逻辑错误,它不是。因此,我不确定它是否真的会返回正确的结果,或者它是否会崩溃或进入无限循环。不过我没试过。
真的,代码应该直接检查cmax 是否等于Integer.MAX_VALUE,而不是在计算中使用它并希望代码稍后能告诉结果是假的。