【问题标题】:Java Regex Bug with single quote lookup?带有单引号查找的 Java 正则表达式错误?
【发布时间】:2017-01-03 10:29:43
【问题描述】:

可能是一个我还没有看到的 PEBKAC,但是:(?:[^']+|'')+ 应该匹配带有非双引号的字符串(基于 Regex: Match double single quote inside string 并使用 Regex 101 进行测试)。

但是,如果在 Java Pattern 对象中使用上述内容,即Pattern noSingleQuote = Pattern.compile("(?:[^']+|'')+");,则行为如下:

  • 如果匹配的String不包含单引号,一切OK,Matcher返回true(即noSingleQuote.matcher("tester").matches()noSingleQuote.matcher("tes''ter").matches()都OK)
  • 如果匹配的字符串确实包含单引号,则 JDK Matcher 会在内部发生无限循环(即,noSingleQuote.matcher("tes'ter").matches() 会导致无限循环)

在 8u112 本地测试,在线使用Regex Planet

我还没有深入调试过无限循环发生的确切原因和位置。

有什么想法、见解?

更新:给定的示例不会重现所描述的行为,使用 "select x, y, z where x = ''t'';""select x, y, z where x = 't'';" 重现了我上面描述的内容。 这对我来说意味着错误(?)不仅仅是因为单引号。

Update2:它不是一个无限循环,但它似乎与字符串本身的空格数成正比。由于我遇到的生产代码有一个很长的字符串和很多空格,我只是假设它是一个无限循环。过失。

【问题讨论】:

  • 你试过转义' chars吗?
  • @I.G.Pascual 为什么?
  • .. 可能 Java 将' 视为特殊字符,需要转义
  • @I.G.Pascual 我看不出转义单引号会有什么不同,但我测试了它:用 \\ 或 \\\\ 转义所有单引号并没有什么不同(在输入字符串也不在模式中,也不在两者中)。
  • 刚刚在本地尝试了相同的代码 jdk1.8.0_66 并且运行良好......看起来你的 jdk 搞砸了......

标签: java regex string


【解决方案1】:

我想您遇到了我在Java regex to match start/end tags causes stack overflow 中描述的一个已知问题。简而言之,原因是 Java 正则表达式引擎以低效的方式处理量化的交替,unroll 这样的模式是个好主意。

在您的情况下,模式应定义为

String pattern = "[^']*(?:''[^']*)*";

这里的逻辑是线性的,涉及的回溯要少得多:

  • [^']* - 除' 之外的零个或多个字符
  • (?:''[^']*)* - 零个或多个序列:
    • '' - 双单引号
    • [^']* - 除' 之外的零个或多个字符。

【讨论】:

  • 感谢您提供详细且有来源的答案。正如我在问题的第一句话中所写:这是我没有看到的 PEBKAC :)
【解决方案2】:

我认为你的无限循环在别处。

Pattern p = Pattern.compile("(?:[^']+|'')+");

public void test(String test) {
    System.out.println("\ntest = [" + test + "]");
    Matcher m = p.matcher(test);
    while (m.find()) {
        System.out.println("Found!");
        for (int i = 0; i <= m.groupCount(); i++) {
            System.out.println("Matched (" + i + ") '" + m.group(i) + "'");
        }
    }
}

private void test() {
    test("select x, y, z where x = ''t'';");
    test("select x, y, z where x = 't'';");
    test("tes'ter");

}

工作正常,没有问题。

JDK-1.8.0_111

【讨论】:

  • @WiktorStribiżew - 答案的重点是它应该帮助 OP 解决他们的问题。 - 我怀疑 OP 没有遍历组或 m.find()正确调用。这将证明这样做是正确的。
  • @OldCurmudgeon OP 甚至没有提到matcher#find(),它是关于matcher#matches()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-05
  • 2018-08-02
  • 1970-01-01
  • 2015-03-24
  • 2010-09-18
相关资源
最近更新 更多