【问题标题】:Regular Expression in Java. Unexpected behaviourJava中的正则表达式。意外行为
【发布时间】:2013-01-14 04:20:50
【问题描述】:

我试图匹配大部分数字,但取决于表达式后面的单词,我需要有所作为。

我匹配每个没有后跟温度术语(如°C)或时间规范的数字。 我的正则表达式如下所示:

(((\d+?)(\s*)(\-)(\s*))?(\d+)(\s*))++(?!minuten|Minuten|min|Min|Stunden|stunden|std|Std|°C| °C)

这是一个例子:http://regexr.com?33jeg

虽然这种行为是我所期望的,但 Java 会执行以下操作: 索引是匹配4的对应组

0: "4 "1: "4 "2: "0 - "3: "0"4: " "5: "-"6: " "7: "4"8: " "9: "°C"

您需要知道我将每个字符串单独匹配。所以 5 的比赛看起来像这样:

0: "5 "1: "5 "2: "null"3: "null"4: "null"5: "null"6: "null"7: "5"8: " "9: "null"

这就是我喜欢其他 Match 的方式。这种令人不快的行为仅在匹配之前的字符串中某处出现“-”时

我的 Java 代码如下:

public static void adaptPortionDetails(EList<Step> steps, double multiplicator){
    
    String portionMatcher = "(((\\d+?)(\\s*)(\\-)(\\s*))?(\\d+)(\\s*))++(?!°C|Grad|minuten|Minuten|min|Min|Stunden|stunden|std|Std)";
    
    for (int i = 0; i < steps.size(); i++) {
        Matcher matcher = Pattern.compile(portionMatcher).matcher(
                steps.get(i).getDescription());
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            printGroups(matcher);
            String newValue1Str;
            if (matcher.group(3) == null){
                newValue1Str = "";
                System.out.println("test");
            }else{
                double newValue1 = Integer.parseInt(matcher.group(3)) * multiplicator;
                newValue1Str = Fraction.getFraction(newValue1).toProperString();
            }
            double newValue2 = Integer.parseInt(matcher.group(7)) * multiplicator;
            String newValue2Str = Fraction.getFraction(newValue2).toProperString();
            
            
            matcher.appendReplacement(sb, newValue1Str + "$4$5$6" + newValue2Str + "$8");
        }
        matcher.appendTail(sb);
        steps.get(i).setDescription(sb.toString());
    }
}

希望你能说出我错过了什么。

【问题讨论】:

  • 究竟是什么不愉快的行为 - 你能更清楚地描述它吗?你需要那么多捕获组()吗?
  • 因为组 2 到 7 应该为空。但是例如在第 3 组中,字符串“0”是初始字符串 190 的最后一位。即使整体匹配是我想要的。我真的不需要所有的组。但我需要得到第 3 组和第 7 组,我需要用它们计算一些东西,然后将计算值放在指定位置
  • @lugges:为什么你单独放置的正则表达式与代码中的正则表达式不同?
  • 那是因为在我的原始代码中,我从不同的数组构建了正则表达式,并且我使用了 print 方法并将其作为常量放在这里。我在最初的帖子和我的代码中删除了°C 周围的圆括号。我还缺少另一个区别吗?

标签: java regex parsing matcher


【解决方案1】:

这似乎是 Java 实现中的一个错误(或功能?)。当必须从下一个索引重做匹配时,它似乎不会重置捕获组的捕获文本。

该测试揭示了 Java 正则表达式引擎和 PHP 的 PCRE 之间的行为差​​异。

  • 正则表达式:(\d+(-\d+)?){1}+(?!x)
  • 输入:34 34-43x 78 90
  • Java 结果:3 个匹配项(347890)。第二场比赛的第二个捕获组是-43。第二个捕获组在第 1 场和第 3 场比赛中没有捕获任何东西。
  • PHP result:同样是 3 场比赛,但第二个捕获组没有捕获所有比赛。对于 PHP 的 PCRE 实现,当必须重做匹配时,捕获组的捕获文本会被重置。

这是在 JRE 6 Update 37 和 JRE 7 Update 11 上测试的。

同样的结果,只是为了证明在必须重做匹配时捕获的文本没有被重置:

  • 正则表达式:a(\d+(-\d+)?){1}+(?!x)
  • 输入:a34 a34-43x a78 a90
  • PHP result

关于您的正则表达式的一些评论

我认为++ 应该是{1}+,因为您似乎想一次修改一个数字或一个数字范围,同时使匹配具有所有格以丢弃不需要的数字。

解决方法

第一个组(最外层的捕获组)捕获所有内容(一个数字或一个数字范围),当找到匹配项时将始终被覆盖。因此,您可以依赖它。您可以检查组1中是否存在-(使用contains方法)。如果有,那么您可以判断捕获组 2 包含当前匹配中捕获的文本,并且您可以使用捕获的文本。如果没有,则可以忽略捕获组 2 及其嵌套捕获组中的所有捕获文本。

【讨论】:

  • 谢谢。很高兴知道我理解正确并且行为不合逻辑。您对我有什么建议吗?如何才能获得适合我情况的更好结果
猜你喜欢
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
  • 2013-11-15
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多