【问题标题】:Bug in Java regex implementation?Java 正则表达式实现中的错误?
【发布时间】:2013-02-05 17:05:44
【问题描述】:

我在 Java 的正则表达式实现中发现了一些意外行为。在使用java.util.regex.Pattern 和java.util.regex.Matcher 时,使用Matcher 的find() 方法时,以下正则表达式无法正确匹配输入"Merlot":

((?:White )?Zinfandel|Merlot)

如果我改变最外层匹配组内表达式的顺序,Matcher 的find() 方法确实匹配。

(Merlot|(?:White )?Zinfandel)

这里有一些说明问题的测试代码。

RegexTest.java

import java.util.regex.*;

public class RegexTest {
    public static void main(String[] args) {
        Pattern pattern1 = Pattern.compile("((?:White )?Zinfandel|Merlot)");
        Matcher matcher1 = pattern1.matcher("Merlot");
        // prints "No Match :("
        if (matcher1.find()) {
            System.out.println(matcher1.group(0));
        } else {
            System.out.println("No match :(");
        }

        Pattern pattern2 = Pattern.compile("(Merlot|(?:White )?Zinfandel)");
        Matcher matcher2 = pattern2.matcher("Merlot");
        // prints "Merlot"
        if (matcher2.find()) {
            System.out.println(matcher2.group(0));
        } else {
            System.out.println("No match :(");
        }
    }
}

预期的输出是:

Merlot
Merlot

但实际输出是:

No Match :(
Merlot

我已经验证了这种意外行为存在于 Ubuntu linux 上的 Java 版本 1.7.0_11 和 OSX 10.8.2 上的 Java 版本 1.6.0_37 中。我昨天将此行为作为错误报告给Oracle,并收到一封自动电子邮件,告诉我我的错误报告已收到,内部审核 ID 为 2441589。当我在中搜索该 ID 时找不到我的错误报告他们的错误数据库。 (你能听到蟋蟀的声音吗?)

我是否发现了 Java 可能经过彻底测试和使用的正则表达式实现中的一个错误(在 2013 年很难相信),还是我做错了什么?

【问题讨论】:

  • 如果你这样做(((?:White )?Zinfandel)|Merlot)或((?:(?:White )?Zinfandel)|Merlot)会发生什么?
  • 这可能是范围问题吗?连接是否优先于(如我所料) | (选择)?
  • 看起来 matches() 有效,但 find() 无效。
  • 这是我能找到的最简单的正则表达式,但未能找到:Pattern.compile("()?.|").matcher("").find()
  • 不管怎样,这种行为也存在于 Windows 7 上的 Java 版本 1.7.0_21 上。

标签: java regex


【解决方案1】:

以下内容:

import java.util.regex.*;

public class T {
  public static void main( String args[] ) {
    System.out.println( Pattern.compile("(a)?bb|c").matcher("c").find() );
    System.out.println( Pattern.compile("(a)?b|c").matcher("c").find() );
  }
}

打印

false
true

开:

  • JDK 1.7.0_13
  • JDK 1.6.0_24

以下内容:

import java.util.regex.*;

public class T {
  public static void main( String args[] ) {
    System.out.println( Pattern.compile("((a)?bb)|c").matcher("c").find() );
    System.out.println( Pattern.compile("((a)?b)|c").matcher("c").find() );
  }
}

打印:

true
true

【讨论】:

  • 这似乎证实了这是一个真正的错误。我希望它输出true true。
  • Pattern.compile("(a)?bb|c").matcher("c").matches() 为真
  • @jdb:如上所述,matches() 按预期工作。 find() 是问题所在。不幸的是,如果你需要提取匹配的文本,你必须使用find()。
  • 我的意思是它看起来像一个错误。
  • 给你:Pattern.compile("((?:White )?Zin|Merlot)").matcher("Merlot").find() 是真的
【解决方案2】:

好像是fixed in Java 1.8。

Welcome to Scala version 2.11.0-20130930-063927-2bba779702 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0-ea).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import java.util.regex._
import java.util.regex._

scala> Pattern.compile("((?:White )?Zinfandel|Merlot)")
res0: java.util.regex.Pattern = ((?:White )?Zinfandel|Merlot)

scala> .matcher("Merlot")
res1: java.util.regex.Matcher = java.util.regex.Matcher[pattern=((?:White )?Zinfandel|Merlot) region=0,6 lastmatch=]

scala> .find()
res2: Boolean = true

【讨论】:

    【解决方案3】:

    我不明白发生了什么,但我一直在使用您的示例来尝试提取一些您可以添加到错误报告中的诊断信息。

    首先,如果你使用所有格量词,它会起作用,但我不知道为什么:

    Pattern pattern1 = Pattern.compile("((?:White )?+Zinfandel|Merlot)");

    此外,如果选择中的第一组比第二组短,那么无论哪种方式都可以:

    Pattern pattern1 = Pattern.compile("((?:White )?Zinf|Merlot)");

    就像我说的,我真的不明白这怎么可能。这两个发现对我没有任何意义,但我只是想我会分享......

    【讨论】:

    • 在我的测试中,“Zinf”/“Zinfandel”的长度似乎与模式空间的大小有关。如果你对“Merlot blahblah”运行完整的原始模式,它适合我。也许到达模式空间的末尾会导致它过早退出。
    【解决方案4】:

    该错误显然是 fixed in Java 8,并在 Java 7 中以“无法修复”as a backport 解决。但是,作为一种解决方法,您可以使用独立(原子)分组“White”,或者您可以通过将“White Zinfandel”包装到单独的交替测试组中来隔离“White Zinfandel”的测试用例。

    在您的示例中,在第一个捕获组中有一个 non-capturing group,其中包含以下内容。

    非捕获组修饰符(?:White)

    ((?:White )?Zinfandel|Merlot)
    

    作为一种解决方法,使用 independent capturing group 会成功。

    独立非捕获组修饰符(?>White)

    ((?>White )?Zinfandel|Merlot)
    

    在 Java 1.7.0_71 中为独立的非捕获组或组交替重新创建测试用例是可行的。

    java version "1.7.0_71"
    Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
    Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)
    

    独立非捕获组或组交替

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RegexTest {
    
        public static void main( String[] args ) {
    
            Pattern independentNCG = Pattern.compile( "((?>White )?Zinfandel|Merlot)" );
            Matcher independentNCGMatcher = independentNCG.matcher( "Merlot" );
    
            Pattern alternateGroupPattern = Pattern.compile( "(((?:White )?Zinfandel)|Merlot)" );
            Matcher alternateGroupMatcher = alternateGroupPattern.matcher( "Merlot" );
    
            System.out.println( independentNCGMatcher.find() ? independentNCGMatcher.group( 0 ) : "No match found for Merlot" );
            System.out.println( alternateGroupMatcher.find() ? alternateGroupMatcher.group( 0 ) : "No match found for Merlot" );
    
        }
    }
    

    返回

    Merlot
    Merlot
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    相关资源
    最近更新 更多