ZetCode

Java Matcher 类

上次修改时间:2025 年 4 月 20 日

java.util.regex.Matcher 类用于使用模式对字符序列执行匹配操作。 它根据输入文本解释编译的正则表达式模式以查找匹配项。 Matcher 对象不是线程安全的。

Matcher 提供了执行各种匹配操作、检查匹配结果和修改输入文本的方法。 它与 Pattern 类协同工作,以在 Java 应用程序中提供完整的正则表达式功能。

Matcher 类概述

Matcher 是通过使用输入序列调用 Pattern.matcher 来创建的。 它维护有关当前匹配位置的状态,并提供查询和操作匹配项的方法。 该类支持简单和复杂的匹配场景。

关键方法包括 matchesfindgroup 以及各种替换方法。 Matcher 还支持命名捕获组和区域限制以进行部分匹配。

基本匹配操作

Matcher 类提供了三种基本的匹配方法:matcheslookingAtfind。 每种方法在模式匹配操作中都具有不同的用途。

MatcherBasic.java
package com.zetcode;

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

public class MatcherBasic {

    public static void main(String[] args) {
        
        String input = "The quick brown fox jumps over the lazy dog";
        Pattern pattern = Pattern.compile("quick.*fox");
        
        Matcher matcher = pattern.matcher(input);
        
        // matches() - entire input must match
        System.out.println("matches(): " + matcher.matches());
        
        // lookingAt() - input must match from beginning
        System.out.println("lookingAt(): " + matcher.lookingAt());
        
        // find() - match anywhere in input
        System.out.println("find(): " + matcher.find());
        
        // Reset matcher to start from beginning
        matcher.reset();
        
        // Find all matches
        System.out.println("\nAll matches:");
        while (matcher.find()) {
            System.out.println("Found at: " + matcher.start() + "-" + matcher.end());
        }
    }
}

此示例演示了三种基本的匹配方法。 matches 检查整个输入是否与模式匹配。 lookingAt 检查输入是否以模式开头。 find 在输入中的任何位置搜索该模式。

该示例还显示了如何使用 startend 来获取匹配位置。 reset 将 matcher 重新定位到输入的开头以进行重复搜索。

组捕获

Matcher 支持捕获由正则表达式模式中的括号定义的组。 组允许提取匹配文本的特定部分。 组 0 表示整个匹配,而组 1+ 表示捕获的子模式。

MatcherGroups.java
package com.zetcode;

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

public class MatcherGroups {

    public static void main(String[] args) {
        
        String input = "John Doe, age 30, email: john.doe@example.com";
        Pattern pattern = Pattern.compile(
            "(\\w+ \\w+), age (\\d+), email: (\\S+@\\S+)");
        
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("Name: " + matcher.group(1));
            System.out.println("Age: " + matcher.group(2));
            System.out.println("Email: " + matcher.group(3));
            
            System.out.println("\nGroup count: " + matcher.groupCount());
        }
    }
}

此示例使用捕获组从输入字符串中提取姓名、年龄和电子邮件。 该模式定义了三个用括号括起来的组。 成功匹配后,可以通过其索引检索每个组的内容。

groupCount 返回模式中捕获组的数量(不包括组 0)。 组从左到右根据其左括号进行编号。

命名捕获组

Java 7 引入了使用 (?<name>...) 语法的命名捕获组。 命名组使模式更具可读性,并且匹配更容易处理。 可以使用组名而不是数字索引。

MatcherNamedGroups.java
package com.zetcode;

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

public class MatcherNamedGroups {

    public static void main(String[] args) {
        
        String input = "Date: 2023-05-15, Time: 14:30";
        Pattern pattern = Pattern.compile(
            "Date: (?<date>\\d{4}-\\d{2}-\\d{2}), Time: (?<time>\\d{2}:\\d{2})");
        
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Date: " + matcher.group("date"));
            System.out.println("Time: " + matcher.group("time"));
            
            // Still accessible by index
            System.out.println("\nGroup 1: " + matcher.group(1));
            System.out.println("Group 2: " + matcher.group(2));
        }
    }
}

此示例演示了命名组捕获。 该模式定义了两个命名组:“date”和“time”。 与数字组引用相比,这些名称使代码更具可读性和可维护性。

命名组仍然可以通过其数字索引访问,从而保持向后兼容性。 组命名语法有助于记录正则表达式本身内的模式结构。

文本替换

Matcher 通过 replaceAllreplaceFirst 方法提供强大的文本替换功能。 这些方法允许使用文字字符串或组引用来转换匹配的文本。

MatcherReplace.java
package com.zetcode;

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

public class MatcherReplace {

    public static void main(String[] args) {
        
        String input = "User: john_doe, Email: john@example.com";
        Pattern pattern = Pattern.compile("(\\w+)@(\\w+\\.\\w+)");
        
        Matcher matcher = pattern.matcher(input);
        
        // Replace first match
        String firstReplaced = matcher.replaceFirst("EMAIL_REDACTED");
        System.out.println("First replaced: " + firstReplaced);
        
        // Replace all matches
        String allReplaced = matcher.replaceAll("$1@DOMAIN.REDACTED");
        System.out.println("All replaced: " + allReplaced);
        
        // Append replacement using appendReplacement/appendTail
        matcher.reset();
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1) + "@NEW.DOMAIN");
        }
        matcher.appendTail(sb);
        System.out.println("Custom replacement: " + sb.toString());
    }
}

此示例显示了三种替换技术。 replaceFirst 仅替换第一个匹配项,而 replaceAll 替换所有匹配项。 美元符号表示法 ($1) 引用捕获的组。

对于更复杂的替换,appendReplacementappendTail 提供细粒度控制。 这些方法允许单独处理匹配项,同时以增量方式构建结果。

区域操作

Matcher 支持区域限制,以将匹配限制为输入的一部分。 region 方法定义了匹配操作的边界,而 useAnchoringBoundsuseTransparentBounds 控制边界行为。

MatcherRegion.java
package com.zetcode;

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

public class MatcherRegion {

    public static void main(String[] args) {
        
        String input = "Start: 123 Middle: 456 End: 789";
        Pattern pattern = Pattern.compile("\\d+");
        
        Matcher matcher = pattern.matcher(input);
        
        // Set region from index 10 to 25
        matcher.region(10, 25);
        
        System.out.println("Region matches:");
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group() + 
                " at " + matcher.start());
        }
        
        // Check anchoring bounds behavior
        matcher.region(15, 25);
        matcher.useAnchoringBounds(false);
        System.out.println("\nWithout anchoring bounds:");
        System.out.println("^ matches: " + matcher.hitEnd());
    }
}

此示例演示了区域操作。 第一部分将匹配限制为输入的字符 10-25,有效地跳过“Start: 123”和“End: 789”。 仅找到指定区域内的数字。

第二部分显示了锚定边界如何影响模式匹配。 禁用后,^ 和 $ 锚点将不会在区域边界处匹配。 hitEnd 指示匹配是否到达输入区域的末尾。

使用标志进行模式匹配

Matcher 从其 Pattern 对象继承模式标志,但可以覆盖某些行为。 useCaseInsensitive 方法启用不区分大小写的匹配,而无需重新创建 matcher。

MatcherFlags.java
package com.zetcode;

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

public class MatcherFlags {

    public static void main(String[] args) {
        
        String input = "The Quick BROWN fox JUMPS over the lazy DOG";
        Pattern pattern = Pattern.compile("\\b[a-z]+\\b");
        
        Matcher matcher = pattern.matcher(input);
        
        System.out.println("Default matching (case sensitive):");
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
        
        // Enable case-insensitive matching
        matcher.reset();
        matcher.useCaseInsensitive(true);
        
        System.out.println("\nCase-insensitive matching:");
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}

此示例显示了如何在创建 matcher 后修改匹配行为。 第一次传递使用区分大小写的匹配,仅查找小写单词。 启用不区分大小写的模式后,所有单词都将被匹配,而不管大小写如何。

reset 在将 matcher 重用于新标志之前清除其状态。 当只需要更改标志时,此方法比创建新的 matcher 更有效。

来源

Java Matcher 类文档

本教程介绍了 Java Matcher 类的重要方法和功能。 掌握这些概念对于在 Java 应用程序中使用正则表达式进行有效的文本处理至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员。我于 2007 年开始撰写编程文章,至今已创作了 1400 多篇文章和 8 本电子书。拥有超过 8 年的教学经验,我致力于分享我的知识,帮助他人掌握编程概念。

列出所有Java教程