Java中的正则表达式。意外的行为

时间:2013-01-30 11:07:21

标签: java regex parsing matcher

我正在尝试匹配大多数数字,但根据表达式的字词,我需要有所作为。

我匹配每个未跟随温度条件的数字,如°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"

这就像其他匹配一样。这种不愉快的行为只有在匹配前的字符串

中有“ - ”时才会出现

我的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());
    }
}

希望你能说出我所缺少的东西。

1 个答案:

答案 0 :(得分:0)

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

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

  • 正则表达式:(\d+(-\d+)?){1}+(?!x)
  • 输入:34 34-43x 78 90
  • Java结果:3场比赛(347890)。第二场比赛的第二场比赛是-43。第二个捕获组没有捕获第一和第三场比赛的任何内容。
  • 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及其嵌套捕获组中捕获的所有文本。