我们可以在 lookbehind 表达式中使用量词吗?
Can we use quantifiers inside a lookbehind expression?
此问题特定于 Java 7/8。
使用量词的相当复杂的正则表达式在后向断言中被禁止使用,例如:
(?<=(a|b*)*)bc
因为它会导致运行时异常并显示如下消息:
look-behind group does not have obvious maximum length error
我猜这是因为 *
和 +
等量词是 "generally" 不允许的。
但是,以下内容确实有效:
(?<=a*)bc
为什么会这样?
SO 上有关于此问题的类似帖子:
对于其他语言:
ruby, PCRE等-
有些帖子是针对 Java 的,但似乎没有提供具体的答案或参考资料,例如 this one. Mostly the answers state these quantifiers simply cannot be used. Also, 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
是"expression"的最大长度,cmax
是量词的上界,maxL
是"prefix"的最大长度。当量词为 *
或 +
时,上限设置为 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
似乎应该抛出异常,但由于错误的溢出检查逻辑,事实并非如此。因此,我不确定它实际上是否会 return 正确的结果,或者它是否会崩溃或进入无限循环。不过,我没试过。
真的,代码应该直接检查 cmax
是否等于 Integer.MAX_VALUE
,而不是在计算中使用它并希望代码稍后可以告诉结果是假的。
此问题特定于 Java 7/8。
使用量词的相当复杂的正则表达式在后向断言中被禁止使用,例如:
(?<=(a|b*)*)bc
因为它会导致运行时异常并显示如下消息:
look-behind group does not have obvious maximum length error
我猜这是因为 *
和 +
等量词是 "generally" 不允许的。
但是,以下内容确实有效:
(?<=a*)bc
为什么会这样?
SO 上有关于此问题的类似帖子:
对于其他语言: ruby, PCRE等-
有些帖子是针对 Java 的,但似乎没有提供具体的答案或参考资料,例如 this one. Mostly the answers state these quantifiers simply cannot be used. Also, 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
是"expression"的最大长度,cmax
是量词的上界,maxL
是"prefix"的最大长度。当量词为 *
或 +
时,上限设置为 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
似乎应该抛出异常,但由于错误的溢出检查逻辑,事实并非如此。因此,我不确定它实际上是否会 return 正确的结果,或者它是否会崩溃或进入无限循环。不过,我没试过。
真的,代码应该直接检查 cmax
是否等于 Integer.MAX_VALUE
,而不是在计算中使用它并希望代码稍后可以告诉结果是假的。