如何从字符串Regex中提取数据

时间:2017-03-06 01:34:31

标签: java regex

为什么在这段代码中我必须重复3次正则表达式模式才能找到3个单独的数字?我想只使用".*(\\d{10}+).*"来查找字符串word中的所有数字,但我必须重复3次,为什么这就是我做错了?

    public static void main (String [] args){

    String word = " Some random mobile numbers 0546 105 610, 451 518 9675, 54 67892 541";
    word = word.replaceAll("\\s+","");

    Pattern pat = Pattern.compile(".*(\\d{10}+).*"+".*(\\d{10}+).*"+".*(\\d{10}+).*");
    Matcher mat = pat.matcher(word);

    while (mat.find()) {
        for (int i = 1; i <= mat.groupCount(); i++) {
            System.out.println(mat.group(i));
        }
    } 

}

3 个答案:

答案 0 :(得分:1)

这是因为.*是一种贪婪的模式(参见Regex Quantifiers),这意味着它会尝试尽可能多地从字符串中进食,同时仍然可以获得匹配。因此,在您的情况下,它将捕获除最后一个之外的所有数字。

为了解决这个问题,你应该摆脱匹配所有模式.*,因为find已经可以获得与之间任何内容的所有匹配。

所以只使用(\\d{10})就可以了。

public static void main (String [] args){
    String word = " Some random mobile numbers 0546 105 610, 451 518 9675, 54 67892 541";
    word = word.replaceAll("\\s+","");

    Pattern pat = Pattern.compile("(\\d{10})");
    Matcher mat = pat.matcher(word);

    while (mat.find()) {
        for (int i = 1; i <= mat.groupCount(); i++) {
            System.out.println(mat.group(i));
        }
    }
}

答案 1 :(得分:1)

@Hesham Attia的回答非常简单,可以解决您的问题,只需要解释一下它与原始模式的不同之处。

让我们将匹配组的索引i添加到代码中:

    public static void main(String[] args) throws IOException {
    String word = " Some random mobile numbers 0546 105 610, 451 518 9675, 54 67892 541";
    word = word.replaceAll("\\s+", "");

    Pattern pat = Pattern.compile("(\\d{10})");
    Matcher mat = pat.matcher(word);

    while (mat.find()) {
        for (int i = 1; i <= mat.groupCount(); i++) {
            System.out.println("Group-" + i + ": " + mat.group(i));
        }
    }
}

你将得到结果:

  

Group-1:0546105610

     

Group-1:4515189675

     

Group-1:5467892541

pattern的结果是:

  

Group-1:0546105610

     

Group-2:4515189675

     

Group-3:5467892541

实际上,新pattern "(\\d{10})"的上述代码与以下代码相同:

    public static void main(String[] args) throws IOException {
    String word = " Some random mobile numbers 0546 105 610, 451 518 9675, 54 67892 541";
    word = word.replaceAll("\\s+", "");

    Pattern pat = Pattern.compile("\\d{10}");
    Matcher mat = pat.matcher(word);

    while (mat.find()) {
        System.out.println(mat.group());
    }
}

如果你引用Matcher.find(), Matcher.group(), Matcher.groupCount()的javadoc,你会发现方法Matcher.find()尝试找到给定模式的下一个匹配子字符串,Matcher.group()返回上一个匹配,并且Matcher.groupCount()不包括整个匹配(组0),只包括模式中指定的捕获组。

简单地说,正则表达式引擎的工作方式是它将使用主题子序列遍历您的模式并尝试尽可能匹配(贪婪模式),现在让我们谈谈这些模式之间的差异:

  1. 您的原始模式".*(\\d{10}+).*"+".*(\\d{10}+).*"+".*(\\d{10}+).*"why you need repeat it three times

    如果仅给出".*(\\d{10}+).*",则模式将匹配整个字符串,匹配的部分为:

    • &#34; Somerandommobilenumbers&#34;匹配标题.*
    • &#34; 0546105610&#34;匹配\\d{10}+并转到第1组
    • &#34;,4515189675,5467892541&#34;匹配尾部.*

    整个字符串已经用于第一次尝试,并且没有任何东西让模式再次匹配,你只是无法提取第二和第三个数字,所以你需要重复你的模式将它们分成几组。

  2. 模式 "(\\d{10})"

    每次调用mat.find()时,它会匹配一个数字序列,将其放入第1组并返回,然后您可以从第1组中提取结果,这就是为什么组的索引总是 1

  3. 模式 "\\d{10}"

    模式2 相同,但不会将匹配结果添加到组1,因此您可以直接从mat.group()获取结果,实际上它是0组

答案 2 :(得分:-1)

您真正的问题是您正在使用Pattern,这很容易出错,因为它需要大量代码;这是你如何在一个简单的行中完成的:

String[] numbers = word.replaceAll("[^\\d,]", "").split(",");