Java正则表达式中matches()和find()的区别

308

我想了解matches()find()之间的区别。

根据Javadoc(据我所知),matches()将搜索整个字符串,即使它找到了它要查找的内容,而find()会在找到它要查找的内容时停止。

如果这个假设是正确的,除非你想计算它发现的匹配数,否则我看不到你何时需要使用matches()而不是find()

在我看来,String类应该有一个内置方法find()而不是matches()

因此,总结一下:

  1. 我的假设正确吗?
  2. 什么情况下使用matches()比使用find()更有用?

7
请注意,对于同一个Matcher对象,多次调用find()方法可能会返回不同的结果。请参考下面的答案。 - L. Holanda
这个问题涉及到 java.util.regex.Pattern.compile(regex).matcher(input).matches()java.util.regex.Pattern.compile(regex).matcher(input).find() - Jens Piegsa
5个回答

360

matches试图将表达式与整个字符串匹配,并隐式地在模式的开头添加^,在末尾添加$,这意味着它不会查找子字符串。 因此,此代码的输出为:

public static void main(String[] args) throws ParseException {
    Pattern p = Pattern.compile("\\d\\d\\d");
    Matcher m = p.matcher("a123b");
    System.out.println(m.find());
    System.out.println(m.matches());

    p = Pattern.compile("^\\d\\d\\d$");
    m = p.matcher("123");
    System.out.println(m.find());
    System.out.println(m.matches());
}

/* output:
true
false
true
true
*/
123a123b的子字符串,所以find()方法输出true。matches()只会“看到”a123b,这与123不同,因此输出false。

34
这个答案是误导性的。matchers() 不仅仅是一个带有隐含前置符^和后置符$的 find()。请注意,如果未在 reset() 前调用 .find() 多次,则可能会得到不同的结果,而 matches() 总是返回相同的结果。请参见下面的我的回答。 - L. Holanda

104

matches函数会在整个字符串与给定的模式完全匹配时返回true。而find函数则是尝试找到一个与模式匹配的子字符串。


57
如果这样更清晰的话,你可以说matches(p)find("^" + p + "$")是相同的。 - jensgram
7
举个例子来说明答案:在字符串 "123abc123" 中,正则表达式 "[a-z]+" 会在使用 matches() 方法时失败,但在使用 find() 方法时成功。 - bezmax
4
@Max 说得对,"123abc123".matches("[a-z]+") 会失败,就像 "123abc123".find("^[a-z]+$") 一样。我的观点是,matches() 要求完全匹配,就像同时使用起始和结束锚点的 find() 一样。 - jensgram
5
Pattern.compile("some pattern").matcher(str).matches() 等同于 Pattern.compile("^some pattern$").matcher(str).find() - AlexR
3
...("some pattern").matcher(str).matches()并不完全等同于...("^some pattern$").matcher(str).find(),只有在第一个调用中才是这样。请参见下面的答案。 - L. Holanda
显示剩余2条评论

84
  • matches() - 仅当整个字符串匹配时才会返回true
  • find() - 尝试在与正则表达式匹配的子字符串中查找下一个匹配项。

请注意,在find()的情况下强调了"下一个"。这意味着,多次调用find()的结果可能不同。此外,通过使用find(),您可以调用start()来返回子字符串匹配的位置。


示例

final Matcher subMatcher = Pattern.compile("\\d+").matcher("skrf35kesruytfkwu4ty7sdfs");
System.out.println("Found: " + subMatcher.matches());
System.out.println("Found: " + subMatcher.find() + " - position " + subMatcher.start());
System.out.println("Found: " + subMatcher.find() + " - position " + subMatcher.start());
System.out.println("Found: " + subMatcher.find() + " - position " + subMatcher.start());
System.out.println("Found: " + subMatcher.find());
System.out.println("Found: " + subMatcher.find());
System.out.println("Matched: " + subMatcher.matches());

System.out.println("-----------");
final Matcher fullMatcher = Pattern.compile("^\\w+$").matcher("skrf35kesruytfkwu4ty7sdfs");
System.out.println("Found: " + fullMatcher.find() + " - position " + fullMatcher.start());
System.out.println("Found: " + fullMatcher.find());
System.out.println("Found: " + fullMatcher.find());
System.out.println("Matched: " + fullMatcher.matches());
System.out.println("Matched: " + fullMatcher.matches());
System.out.println("Matched: " + fullMatcher.matches());
System.out.println("Matched: " + fullMatcher.matches());

输出

Found: false
Found: true - position 4
Found: true - position 17
Found: true - position 20
Found: false
Found: false
Matched: false
-----------
Found: true - position 0
Found: false
Found: false
Matched: true
Matched: true
Matched: true
Matched: true

所以,如果Matcher对象没有被重置,请谨慎多次调用find(),即使正则表达式使用^$匹配整个字符串。


3
非常有帮助,伙计。 - DockYard

7

find()会将子字符串与正则表达式进行匹配,而matches()则会将整个表达式作为一个整体进行匹配。

find()仅在子字符串与模式匹配时返回true。

public static void main(String[] args) {
        Pattern p = Pattern.compile("\\d");
        String candidate = "Java123";
        Matcher m = p.matcher(candidate);

        if (m != null){
            System.out.println(m.find());//true
            System.out.println(m.matches());//false
        }
    }

3

matches(); 没有缓存,但是 find() 会缓存。 find() 首先搜索整个字符串,索引结果,并返回布尔值和相应的索引。

这就是为什么当你有像下面的代码时:

1:Pattern.compile("[a-z]");

2:Pattern.matcher("0a1b1c3d4");

3:int count = 0;

4:while(matcher.find()){

5:count++: }

第四步,使用模式结构的正则表达式引擎将按照regex[single character]指定的索引逐个读取您的代码,以查找至少一个匹配项。如果找到了这样的匹配项,它将被索引,然后循环将基于索引结果执行;否则,如果它没有像matches()一样进行前向计算,则while语句将永远不会执行,因为匹配字符串的第一个字符不是字母。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接