你能解释一下这个Java Regex情况的奇怪行为吗?

时间:2013-04-11 12:51:24

标签: java regex

我一直在使用以下代码尝试从我提供的文本中提取不同的部分。

它应该选出数字,然后将[括号或"引号括起来的任何部分放入组中。这是代码。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Launcher2 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        PrintRegexes("100.000[$₮-45]");
    }
    public static void PrintRegexes(String textToMatch){
        Pattern p = Pattern.compile("(\\[.*?\\]|\".*?\")?.*?(\\d{1,3}(?:,\\d{3})*?(?:\\.\\d+)?).*?(\\[.*?\\]|\".*?\")",Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Matcher m = p.matcher(textToMatch);
        if (m.find())
        {
            for(int groups =0;groups<m.groupCount();groups++){
                System.out.println("Group "+groups+" contains "+m.group(groups));
            }
            for(int groups =0;m.find(groups);groups++){ //this will error, but right now, it's the least of my concerns
                System.out.println("Group "+groups+" contains "+m.group(groups));
            }
        }

    }
}

Group 0 contains 100.000[$₮-45]
Group 1 contains null
Group 2 contains 100.000
Group 3 contains [$₮-45]
Group 0 contains 100.000[$₮-45]
Group 1 contains null
Group 2 contains 0.000
Group 3 contains [$₮-45]
Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 4 //don't care about this, I've got bigger strings(fish) to regex(fry) at the moment!
    at java.util.regex.Matcher.group(Unknown Source)
    at Launcher2.PrintRegexes(Launcher2.java:21)
    at Launcher2.main(Launcher2.java:10)

group 2外,所有群组都相同,其中一个打印为0.000,另一个打印为100.000

为什么会这样?

如果我发现并且在数字后面,那么这种行为就会消失。

如果我只是把一些东西放在前面,我得到这个输出:

Group 0 contains [$₮-45]100.000
Group 1 contains [$₮-45]
Group 2 contains 100.000
Group 3 contains null
Group 0 contains [$₮-45]100.000
Group 1 contains null
Group 2 contains 45
Group 3 contains null

甚至更奇怪!最奇怪的部分(对我而言)是可以在www.debuggex.com上使用。

我写错了吗?或者,当这个方法Matcher m = p.matcher(textToMatch);构造它并且影响它的行为时,匹配器是否不能解决这些组?

2 个答案:

答案 0 :(得分:1)

我在这里可以看到两个问题。

首先,您以组为参数多次调用m.find(),这不会像您认为的那样工作。
如果查看JavaDoc for find(int start),您会看到它重置匹配器,然后从输入的指定字符开始重新开始搜索。这解释了在以后的迭代中匹配的较短数字序列。

其次,您需要循环直到groups <= m.groupCount()才能获得所有群组:

    Pattern p =
            Pattern.compile("(\\[.*?\\]|\".*?\")?.*?(\\d{1,3}(?:,\\d{3})*?(?:\\.\\d+)?).*?(\\[.*?\\]|\".*?\")",
                Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
    Matcher m = p.matcher(textToMatch);
    if (m.find()) {
        for (int groups = 0; groups <= m.groupCount(); groups++) {
            System.out.println("Group " + groups + " contains " + m.group(groups));
        }
    }

打印

  

组0包含100.000 [$₮-45]
  第1组包含null   第2组包含100.000
  第3组包含[$₮-45]

答案 1 :(得分:0)

问题出在这个部分:(?:,\\d{3})*?

我认为你需要((?:,\\d{3})*)?