模式编译。*? vs。*

时间:2015-11-21 07:21:49

标签: java

我发现了一个区别,但我无法解释:

public static void main(String[] args) {
    Pattern p = Pattern.compile("[+-]?\\d+.*?");
    Matcher m = p.matcher("+5.0h");
    System.out.println(m.matches());                                  //prints true

    Scanner in = new Scanner("+5.0h");
    while (in.hasNext()) {
        if (in.hasNext(p)) {
            System.out.println(in.findInLine(p));                      //prints +5
        }
    }
    in.close();

    System.out.println("6.0hgf".matches("[+-]?\\d+.*?"));   //prints nothing,it seemed that this sentence didn't execute,why this happened?
}  

当我改变了

Pattern p = Pattern.compile("[+-]?\\d+.*?")

Pattern p = Pattern.compile("[+-]?\\d+.*")

发生了以下情况:

public static void main(String[] args) {
    Pattern p = Pattern.compile("[+-]?\\d+.*");
    Matcher m = p.matcher("+5.0h");
    System.out.println(m.matches());                                  //prints true

    Scanner in = new Scanner("+5.0h");
    while (in.hasNext()) {
        if (in.hasNext(p)) {
            System.out.println(in.findInLine(p));                      //prints +5.0h
        }
    }
    in.close();

    System.out.println("6.0hgf".matches("[+-]?\\d+.*?"));   //prints true
} 

所以我想知道为什么会这样?

4 个答案:

答案 0 :(得分:1)

好吧,.是任意字符(不是明确的小数点)然后你有两个不同的东西,*,这是一个贪婪的量词,为零或更多次*? 1}}这是同一事物的一个不情愿的量词(见Differences Among Greedy, Reluctant, and Possessive Quantifiers)。

因此,不情愿的版本"[+-]?\\d+.*?"允许读取+以查找匹配项,并找到一个或多个数字(贪婪)。然后它会查找任意字符0次或更多次,并使用任意字符找到匹配0次(因此尾随.*?基本上没有意义)。

贪婪版本"[+-]?\\d+.*"以相同的方式启动,允许+以便找到与数字匹配的内容;但是然后吞噬了它可以得到的所有任何字符,这当然是字符串的其余部分。

最后,第一个版本中的错误(使用"[+-]?\\d+.*?")源于您使用Scanner的hasNext(String pattern)方法的方式,这是与下一个标记的比较。由于第一次迭代删除了"+5",剩余的下一个标记为".0h",因此条件评估如下:

while (in.hasNext()) { //true, we have ".0h"
    if (in.hasNext(p)) { //false, ".0h" does not begin with +,-, or digit
        System.out.println(in.findInLine(p)); //no longer called, scanner doesn't advance
    }
}

很自然地,循环之后的行永远不会到达。

相比之下,贪婪版本(使用" [+ - ]?\ d +。*")第一次迭代in.findInLine(p)获取整个字符串,所以现在{{ 1}}为false,循环终止。

答案 1 :(得分:1)

*的默认行为是尽可能多地匹配,在?之后确定它只与必要的匹配。

代表:

如果我有字符串"abc"并且我使用.*,它将匹配整个字符串,但如果我将正则表达式更改为.*?,它将无法匹配任何内容,因为*是0或更多。

我们也可以以+为例,如果字符串再次为"abc"而regex为.+,则它将匹配整个字符串,但如果正则表达式为.+?则会只匹配一个字符,在本例中为a

答案 2 :(得分:0)

.*消耗尽可能多的字符(足够匹配(贪婪)

.*?消耗的字符数最少,足以匹配

你的第一个例子是匹配整个词:

Matcher m = p.matcher("+5.0h");
System.out.println(m.matches());

这意味着给出了匹配字,并且没有不同数量的匹配字符的空间。

您的下一个示例尝试查找模式:

in.findInLine(p)

后一种模式将找到匹配字符数最少的匹配,另一种匹配字符匹配次数最多。

最后一个例子对我来说是不可复制的:true在这两种情况下。

答案 3 :(得分:0)

其他答案解释了.*.*?之间的区别。要回答你的另一个问题,为什么System.out.println在第一种情况下没有执行:问题在于你的循环:

while (in.hasNext()) {
    if (in.hasNext(p)) {
        System.out.println(in.findInLine(p));                  //prints +5
    }
}

如果有更多数据要扫描,但它与模式不匹配,则这是一个无限循环。不会消耗任何内容,代码会一遍又一遍地检查同一输入文本上的hasNext()hasNext(p)。因此,如果代码与模式不匹配,您需要重新考虑您希望代码执行的操作。

当您使用.*时没有发生这种情况的原因是.*导致其余输入被吞噬。这意味着in.hasNext()下次返回false,因为没有更多输入。

相关问题