此问题特定于 Java 7/8。
使用量词的相当复杂的正则表达式在像这样的后向断言中是被禁止的:
(?<=(a|b*)*)bc
因为它会导致运行时异常并显示如下消息:
look-behind group does not have obvious maximum length error
我猜这是因为 *
和 +
这样的量词“通常”是不允许的。
但是,以下内容确实有效:
(?<=a*)bc
为什么会这样?
SO 上有关于此问题的类似帖子:
有些帖子专门针对 Java,但似乎没有提供具体的答案或引用,例如 this一。大多数答案表明这些量词根本无法使用。另外,regular-expressions网站声明相同。
This post声明 Java 在其实现背后存在缺陷。
但是,我上面显示的示例在后视中使用零个或多个量词 *
对 Java 7/8 有效。
任何引用资料或解释都会有所帮助。
最佳答案
查看 Pattern
后代码并试图对其进行跟踪,我确信这只是一个错误。这两个示例都应导致异常。但是对此进行测试的逻辑是不正确的。
此代码出现在几个地方:
temp = info.maxLength * cmax + maxL;
info.maxLength = temp;
if (temp < maxL) {
info.maxValid = false;
}
注意只要maxLength
和 cmax
是非负的,temp
绝不能小于 maxL
除非发生溢出。 maxValid
最终由lookbehind代码使用;如果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
.这总是真实的,微不足道的。因此,lookbehind 在这里没有任何意义。同样,
(?<=a+)bc
相当于
(?<=a)bc
因为只要有一个a
在当前位置之前,可能还有多少并不重要。所有不抛出异常的例子都一样,除了这个:
(?<=x(abc)*)bc // succeeds
因为这里匹配器确实必须向后寻找abc
在字符串中并确保最后一个前面有 x
.似乎Pattern
在这种情况下应该抛出异常,但由于错误的溢出检查逻辑,它不是。因此,我不确定它是否真的会返回正确的结果,或者它是否会崩溃或进入无限循环。但是,我还没有尝试过。
真的,代码应该直接检查是否cmax
等于Integer.MAX_VALUE
,而不是在计算中使用它并希望代码可以稍后告诉结果是假的。
关于java - 我们可以在 lookbehind 表达式中使用量词吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37043192/