Java正则表达式-匹配器

时间:2020-01-09 10:35:40  来源:igfitidea点击:

JavaMatcher类(java.util.regex.Matcher)用于在文本中搜索正则表达式的多次出现。我们还可以使用Matcher在不同的文本中搜索相同的正则表达式。

JavaMatcher类具有许多有用的方法。在本教程中,我将介绍JavaMatcher类的核心方法。有关完整列表,请参见Matcher类的官方JavaDoc。

Java Matcher示例

这是一个简单的JavaMatcher示例,因此我们可以了解Matcher类的工作原理:

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

public class MatcherExample {

    public static void main(String[] args) {

        String text    =
            "This is the text to be searched " +
            "for occurrences of the http:// pattern.";

        String patternString = ".*http://.*";

        Pattern pattern = Pattern.compile(patternString);

        Matcher matcher = pattern.matcher(text);
        boolean matches = matcher.matches();
    }
}

首先,从一个正则表达式创建一个" Pattern"实例,然后从" Pattern"实例创建一个" Matcher"实例。然后,在Matcher实例上调用matches()方法。如果正则表达式与文本匹配,则matches()返回true,否则返回false。

我们可以使用Matcher类做更多的事情。其余内容将在本教程的其余部分中介绍。我的Java Regex Pattern教程中单独介绍了Pattern类。

创建一个匹配器

通过Pattern类中的matcher()方法来创建Matcher。这是一个例子:

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

public class CreateMatcherExample {

    public static void main(String[] args) {

        String text    =
            "This is the text to be searched " +
            "for occurrences of the http:// pattern.";

        String patternString = ".*http://.*";

        Pattern pattern = Pattern.compile(patternString);

        Matcher matcher = pattern.matcher(text);
    }
}

在该示例的最后," matcher"变量将包含一个" Matcher"实例,该实例可用于将用于创建它的正则表达式与不同的文本输入进行匹配。

matches()

在创建"匹配器"时,"匹配器"类中的"匹配"方法将正则表达式与传递给"模式。匹配器()"方法的整个文本进行匹配。这是一个Matcher.matches()示例:

String patternString = ".*http://.*";
Pattern pattern = Pattern.compile(patternString);

boolean matches = matcher.matches();

如果正则表达式匹配整个文本,那么matches()方法将返回true。如果不是,则matches()方法返回false。

我们不能使用matches()方法来搜索文本中多次出现的正则表达式。为此,我们需要使用find()start()end()方法。

lookingAt()

MatcherlookingAt()方法的工作方式与matches()方法类似,但有一个主要区别。 LookingAt()方法只将正则表达式与文本的开头匹配,而matches()方法则将正则表达式与整个文本匹配。换句话说,如果正则表达式匹配文本的开头而不是整个文本,则" lookingAt()"将返回true,而" matches()"将返回false。

这是一个Matcher.lookingAt()示例:

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

public class CreateMatcherExample {

    public static void main(String[] args) {

        String text    =
                "This is the text to be searched " +
                "for occurrences of the http:// pattern.";

        String patternString = "This is the";

        Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(text);

        System.out.println("lookingAt = " + matcher.lookingAt());
        System.out.println("matches   = " + matcher.matches());
    }
}

本示例将正则表达式" this is"与文本开头和整个文本匹配。将正则表达式与文本的开头匹配(" lookingAt()")将返回true。

将正则表达式与整个文本匹配(matches())将返回false,因为文本比正则表达式具有更多的字符。正则表达式表示文本必须与文本" This is the"完全匹配,表达式前后均不得有多余的字符。

find()+ start()+ end()

当创建"匹配器"时,"匹配器" find()方法在传递给" Pattern.matcher(text)"方法的文本中搜索正则表达式的出现。如果在文本中可以找到多个匹配项,则find()方法将找到第一个匹配项,然后对于随后的对find()的每次调用,它将移至下一个匹配项。

start()和end()方法将为找到的匹配开始和结束的文本提供索引。实际上,end()返回匹配部分结尾之后的字符索引。因此,可以在String.substring()调用内使用start()和end()的返回值。

这是一个JavaMatcher``find()start()end()的例子:

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

public class MatcherFindStartEndExample {

    public static void main(String[] args) {

        String text    =
                "This is the text which is to be searched " +
                "for occurrences of the word 'is'.";

        String patternString = "is";

        Pattern pattern = Pattern.compile(patternString);
        Matcher matcher = pattern.matcher(text);

        int count = 0;
        while(matcher.find()) {
            count++;
            System.out.println("found: " + count + " : "
                    + matcher.start() + " - " + matcher.end());
        }
    }
}

本示例将在搜索到的字符串中四次找到模式"是"。打印的输出将是这样的:

found: 1 : 2 - 4
found: 2 : 5 - 7
found: 3 : 23 - 25
found: 4 : 70 - 72

reset()

Matcherreset()方法在Matcher内部内部重置匹配状态。如果我们已经通过find()方法开始匹配字符串中的匹配项,则Matcher将在内部保留有关它在输入文本中搜索了多远的状态。通过调用reset(),匹配将从文本的开头再次开始。

还有一个" reset(CharSequence)"方法。该方法重置" Matcher",并通过作为参数传递的" CharSequence"而不是最初创建" Matcher"的" CharSequence"进行" Matcher"搜索。

group()

假设我们正在搜索文本中的URL,并且想从文本中提取找到的URL。当然,我们可以使用start()和end()方法来执行此操作,但是使用组函数更容易做到这一点。

在正则表达式中,组用括号标记。例如:

(John)

此正则表达式与文本" John"匹配。括号不是所匹配文本的一部分。括号标记一个组。如果在文本中找到匹配项,则可以访问组中正则表达式的一部分。

我们可以使用group(int groupNo)方法访问一个组。正则表达式可以包含多个组。因此,每个组都用单独的括号标记。要访问与特定组中表达式子部分匹配的文本,请将组号传递给group(int groupNo)方法。

数字为0的组始终是整个正则表达式。要访问带有括号的组,我们应该从组号1开始。

这是一个Matcher``group()示例:

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

public class MatcherGroupExample {

    public static void main(String[] args) {

        String text    =
                  "John writes about this, and John writes about that," +
                          " and John writes about everything. "
                ;

        String patternString1 = "(John)";

        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);

        while(matcher.find()) {
            System.out.println("found: " + matcher.group(1));
        }
    }
}

本示例在文本中搜索单词" John"的出现。对于找到的每个匹配项,将提取组号1,这与用括号标记的组匹配。该示例的输出为:

found: John
found: John
found: John

多组

如前所述,正则表达式可以具有多个组。这是一个正则表达式,说明了这一点:

(John) (.+?)

该表达式与文本" John"匹配,后跟一个空格,然后是一个或者多个字符。我们在上面的示例中看不到它,但是最后一组后面也有一个空格。

该表达式在正则表达式中包含一些具有特殊含义的字符。这 。表示"任何字符"。 +表示"一次或者多次",并与关联。 (任何字符,一次或者多次)。这 ?表示"匹配尽可能少的字符"。

这是完整的代码示例:

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

public class MatcherGroupExample {

    public static void main(String[] args) {

        String text    =
                  "John writes about this, and John Doe writes about that," +
                          " and John Wayne writes about everything."
                ;

        String patternString1 = "(John) (.+?) ";

        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);

        while(matcher.find()) {
            System.out.println("found: " + matcher.group(1) +
                               " "       + matcher.group(2));
        }
    }
}

请注意这两个组的引用,以粗体标出。这些组匹配的字符被打印到" System.out"中。这是示例输出的内容:

found: John writes
found: John Doe
found: John Wayne

组内组

可以在正则表达式的组内包含组。这是一个例子:

((John) (.+?))

请注意,前面示例中的两个组现在如何嵌套在一个更大的组中。 (同样,我们不能在表达式的末尾看到空格,但是它在那里)。

当组嵌套在彼此内部时,它们会根据满足组左左括号的时间进行编号。因此,组1是大组。组2是内部带有表达式" John"的组。组3是内部带有表达式"。+?"的组。重要的是要知道何时需要通过groups(int groupNo)方法来引用组。

这是使用上述嵌套组的示例:

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

public class MatcherGroupsExample {

    public static void main(String[] args) {

        String text    =
                  "John writes about this, and John Doe writes about that," +
                          " and John Wayne writes about everything."
                ;

        String patternString1 = "((John) (.+?)) ";

        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);

        while(matcher.find()) {
            System.out.println("found: <"  + matcher.group(1) +
                               "> <"       + matcher.group(2) +
                               "> <"       + matcher.group(3) + ">");
        }
    }
}

这是上面示例的输出:

found: <John writes> <John> <writes>
found: <John Doe> <John> <Doe>
found: <John Wayne> <John> <Wayne>

请注意,第一个组(外部组)匹配的值如何包含两个内部组都匹配的值。

replaceAll()+ replaceFirst()

MatcherreplaceAll()和replaceFirst()方法可用于替换Matcher正在搜索的字符串的一部分。replaceAll()`方法替换正则表达式的所有匹配项。 " replaceFirst()"仅替换第一个匹配项。

在进行任何匹配之前,将重置"匹配器",以便从输入文本的开头开始匹配。

这是两个示例:

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

public class MatcherReplaceExample {

    public static void main(String[] args) {

        String text    =
                  "John writes about this, and John Doe writes about that," +
                          " and John Wayne writes about everything."
                ;

        String patternString1 = "((John) (.+?)) ";

        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);

        String replaceAll = matcher.replaceAll("Joe Blocks ");
        System.out.println("replaceAll   = " + replaceAll);

        String replaceFirst = matcher.replaceFirst("Joe Blocks ");
        System.out.println("replaceFirst = " + replaceFirst);
    }
}

这是示例输出的内容:

replaceAll   = Joe Blocks about this, and Joe Blocks writes about that,
    and Joe Blocks writes about everything.
replaceFirst = Joe Blocks about this, and John Doe writes about that,
    and John Wayne writes about everything.

换行符和下一行的意思实际上不是输出的一部分。我添加了它们以使输出更易于阅读。

请注意,打印的第一个字符串如何将所有出现的John后面加一个单词,然后替换为字符串Joe Blocks。第二个字符串仅替换第一个出现的字符串。

appendReplacement()+ appendTail()

Matcher的appendReplacement()和appendTail()方法用于替换输入文本中的字符串标记,并将结果字符串添加到StringBuffer上。

使用find()方法找到匹配项后,可以调用appendReplacement()。这样做会导致来自输入文本的字符被添加到StringBuffer上,并且匹配的文本将被替换。仅从最后一个匹配的结尾开始直到复制匹配的字符之前的字符。

appendReplacement()方法跟踪已复制到StringBuffer中的内容,因此我们可以继续使用find()搜索匹配项,直到在输入文本中找不到更多匹配项为止。

一旦找到最后一个匹配项,部分输入文本仍不会被复制到StringBuffer中。这是从最后一次匹配的末尾到输入文本末尾的字符。通过调用appendTail(),我们也可以将这些最后一个字符添加到StringBuffer中。

这是一个例子:

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

public class MatcherReplaceExample {

    public static void main(String[] args) {

        String text    =
                  "John writes about this, and John Doe writes about that," +
                          " and John Wayne writes about everything."
                ;

        String patternString1 = "((John) (.+?)) ";

        Pattern      pattern      = Pattern.compile(patternString1);
        Matcher      matcher      = pattern.matcher(text);
        StringBuffer stringBuffer = new StringBuffer();

        while(matcher.find()){
            matcher.appendReplacement(stringBuffer, "Joe Blocks ");
            System.out.println(stringBuffer.toString());
        }
        matcher.appendTail(stringBuffer);

        System.out.println(stringBuffer.toString());
    }
}

注意如何在while(matcher.find())循环内调用appendReplacement(),并在循环之后立即调用appendTail()。

该示例的输出为:

Joe Blocks
Joe Blocks about this, and Joe Blocks
Joe Blocks about this, and Joe Blocks writes about that, and Joe Blocks
Joe Blocks about this, and Joe Blocks writes about that, and Joe Blocks
    writes about everything.

我在最后一行插入了换行符,以使文本更具可读性。在实际输出中不会有换行符。

如我们所见," StringBuffer"是由输入文本中的字符和替换字符组成的,一次匹配。