java - 我们可以在 lookbehind 表达式中使用量词吗?

标签 java regex-lookarounds

此问题特定于 Java 7/8。

使用量词的相当复杂的正则表达式在像这样的后向断言中是被禁止的:

(?<=(a|b*)*)bc

因为它会导致运行时异常并显示如下消息:

look-behind group does not have obvious maximum length error

我猜这是因为 *+ 这样的量词“通常”是不允许的。

但是,以下内容确实有效:

(?<=a*)bc

为什么会这样?

SO 上有关于此问题的类似帖子:

  1. 对于其他语言: ruby , PCRE等等-

  2. 有些帖子专门针对 Java,但似乎没有提供具体的答案或引用,例如 this一。大多数答案表明这些量词根本无法使用。另外,regular-expressions网站声明相同。

  3. This post声明 Java 在其实现背后存在缺陷。

但是,我上面显示的示例在后视中使用零个或多个量词 * 对 Java 7/8 有效。

任何引用资料或解释都会有所帮助。

最佳答案

查看 Pattern 后代码并试图对其进行跟踪,我确信这只是一个错误。这两个示例都应导致异常。但是对此进行测试的逻辑是不正确的。

此代码出现在几个地方:

 temp = info.maxLength * cmax + maxL;
 info.maxLength = temp;
 if (temp < maxL) {
     info.maxValid = false;
 }

注意只要maxLengthcmax是非负的,temp绝不能小于 maxL除非发生溢出。 maxValid最终由lookbehind代码使用;如果maxValidfalse , "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/

相关文章:

java - 获取 Spring 环境作为属性

java - 如何使用RESTEasy返回JSP页面?

正则表达式 : replace a phrase only if NOT preceded by a word

java - 使用正则表达式从字符串中删除特定 XML 标记的所有实例

c# - 当我从条件组中省略 "else"时,为什么 .NET 的正则表达式引擎表现得如此奇怪?

用于选择以 'ing' 结尾的单词的正则表达式,除非

java - 使用java通过麦克风读取音频

java - SQLServerBulkCopy 错误处理

java - Logstash Oracle 驱动程序问题

ruby - Ruby 中具有前瞻功能的正则表达式