27

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

((?:White )?Zinfandel|Merlot)

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

(Merlot|(?:White )?Zinfandel)

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

正则表达式测试.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 年很难相信),还是我做错了什么?

4

4 回答 4

8

以下:

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
于 2013-02-05T17:51:08.817 回答
4

它似乎已在 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
于 2013-10-02T05:35:33.050 回答
2

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

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

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

此外,如果选择中的第一组比第二组短,那么它可以通过以下任何一种方式工作:

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

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

于 2013-02-05T18:51:32.737 回答
2

该错误显然已在 Java 8中修复,并已解决为“不会修复”作为Java 7 的反向移植。但是,作为一种解决方法,您可以为“White”使用独立(原子)分组,也可以隔离测试将“白色仙粉黛”包装成一个单独的交替测试组。

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

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

((?:White )?Zinfandel|Merlot)

作为使用独立捕获组的工作将成功。

独立非捕获组修改器(?>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
于 2014-12-19T22:19:33.510 回答