我发现了一个区别,但我无法解释:
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
}
所以我想知道为什么会这样?
答案 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
,因为没有更多输入。