ZetCode

Java Matcher.group 方法

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

Matcher.group 方法是 Java 正则表达式 API 中 java.util.regex 包的一部分。 它检索由捕获组在匹配操作期间捕获的输入子序列。 组从左到右编号,从 1 开始。

组 0 始终指整个模式匹配。 group 方法有几个重载,允许通过编号或名称访问组。 此方法对于提取匹配文本的特定部分至关重要。

Matcher.group 方法概述

Matcher.group 方法有三个主要变体。 无参数版本返回整个匹配项(组 0)。 int 版本返回指定的编号组。 String 版本返回一个命名的组。

在调用 group 之前,必须使用 findmatches 等方法找到匹配项。 在没有成功匹配的情况下调用 group 将抛出 IllegalStateException

基本组检索

此示例演示了 Matcher.group 的最简单用法,用于提取匹配的文本。 我们将匹配一个日期模式并提取其组件。

MatcherGroupBasic.java
package com.zetcode;

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

public class MatcherGroupBasic {

    public static void main(String[] args) {
        
        String input = "Today is 2025-04-20";
        String regex = "(\\d{4})-(\\d{2})-(\\d{2})";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("Year: " + matcher.group(1));
            System.out.println("Month: " + matcher.group(2));
            System.out.println("Day: " + matcher.group(3));
        }
    }
}

在此示例中,我们匹配 YYYY-MM-DD 格式的日期。 正则表达式有三个捕获组,分别用于年、月和日。 group(0) 返回整个匹配项,而 group(1)group(2)group(3) 返回捕获的组件。

命名组检索

Java 7 引入了命名捕获组,使正则表达式模式更具可读性。 此示例展示了如何将 group 与命名组一起使用。

MatcherGroupNamed.java
package com.zetcode;

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

public class MatcherGroupNamed {

    public static void main(String[] args) {
        
        String input = "Product: Laptop, Price: $999.99";
        String regex = "Product: (?<product>\\w+), Price: \\$(?<price>\\d+\\.\\d{2})";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Product: " + matcher.group("product"));
            System.out.println("Price: " + matcher.group("price"));
            System.out.println("Full match: " + matcher.group(0));
        }
    }
}

此示例使用命名组提取产品和价格信息。 (?<name>...) 语法定义命名组。 我们使用 group("product")group("price") 访问这些组。

多组检索

此示例演示了处理多个匹配项及其组。 我们将从文本中提取所有电话号码及其组件。

MatcherGroupMultiple.java
package com.zetcode;

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

public class MatcherGroupMultiple {

    public static void main(String[] args) {
        
        String input = "Contacts: 123-456-7890, 555-123-4567, 888-999-0000";
        String regex = "(\\d{3})-(\\d{3})-(\\d{4})";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        while (matcher.find()) {
            System.out.println("Full number: " + matcher.group(0));
            System.out.println("Area code: " + matcher.group(1));
            System.out.println("Exchange: " + matcher.group(2));
            System.out.println("Line number: " + matcher.group(3));
            System.out.println("-----");
        }
    }
}

在这里,我们循环处理多个电话号码匹配项。 对于 find 找到的每个匹配项,我们使用 group 提取完整的号码及其组件。 此模式对于处理输入文本中的所有出现非常有用。

可选组处理

正则表达式中的某些组可能是可选的。 此示例展示了在使用 group 时如何安全地处理此类情况。

MatcherGroupOptional.java
package com.zetcode;

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

public class MatcherGroupOptional {

    public static void main(String[] args) {
        
        String[] inputs = {
            "Error: 404 - Not Found",
            "Error: 500",
            "Error: 403 - Forbidden"
        };
        
        String regex = "Error: (\\d+)(?: - (.*))?";
        Pattern pattern = Pattern.compile(regex);
        
        for (String input : inputs) {
            Matcher matcher = pattern.matcher(input);
            if (matcher.matches()) {
                System.out.println("Code: " + matcher.group(1));
                
                // Check if description group was matched
                if (matcher.group(2) != null) {
                    System.out.println("Description: " + matcher.group(2));
                } else {
                    System.out.println("No description provided");
                }
                System.out.println("-----");
            }
        }
    }
}

此示例处理描述部分可选的错误消息。 我们使用 matches 进行全字符串匹配,并在访问组 2 之前检查它是否存在。 (?:...) 创建一个非捕获组。

组计数和验证

在访问组之前,最好验证它们是否存在。 此示例展示了如何使用 groupCount 并检查有效组。

MatcherGroupValidation.java
package com.zetcode;

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

public class MatcherGroupValidation {

    public static void main(String[] args) {
        
        String input = "Coordinates: (12.34, 56.78)";
        String regex = "\\((\\d+\\.\\d+), (\\d+\\.\\d+)\\)";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Total groups: " + matcher.groupCount());
            
            try {
                // Attempt to access a non-existent group
                System.out.println("Group 3: " + matcher.group(3));
            } catch (IndexOutOfBoundsException e) {
                System.out.println("Error: " + e.getMessage());
            }
            
            // Safe group access
            for (int i = 0; i <=  matcher.groupCount(); i++) {
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
        }
    }
}

此示例演示了正确的组验证。 groupCount 返回捕获组的数量(不包括组 0)。 我们展示了访问组的错误方式和安全方式,包括错误处理。

高级组替换

组通常用于文本替换操作。 此示例展示了如何在替换字符串中引用组。

MatcherGroupReplacement.java
package com.zetcode;

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

public class MatcherGroupReplacement {

    public static void main(String[] args) {
        
        String input = "Name: John Doe, Age: 30, Occupation: Developer";
        String regex = "Name: (\\w+ \\w+), Age: (\\d+), Occupation: (\\w+)";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.matches()) {
            // Reconstruct string using groups
            String reconstructed = String.format(
                "Occupation: %3$s, Name: %1$s, Age: %2$s",
                matcher.group(1), matcher.group(2), matcher.group(3));
            
            System.out.println("Original: " + input);
            System.out.println("Reconstructed: " + reconstructed);
            
            // Using replaceAll with group references
            String swapped = matcher.replaceAll(
                "Age: $2, Name: $1, Job: $3");
            System.out.println("Swapped: " + swapped);
        }
    }
}

此示例展示了两种在替换中使用组的方法。 首先,我们使用 String.format 手动重建字符串。 然后,我们使用 replaceAll$n 组引用。 两种方法都使用捕获组重新排列信息。

嵌套组访问

正则表达式模式可以有嵌套组。 此示例演示了如何访问复杂模式中组内的组。

MatcherGroupNested.java
package com.zetcode;

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

public class MatcherGroupNested {

    public static void main(String[] args) {
        
        String input = "Version: 2.1.8 (Stable)";
        String regex = "Version: ((\\d+)\\.(\\d+)\\.(\\d+)) \\(([A-Za-z]+)\\)";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.matches()) {
            System.out.println("Full version: " + matcher.group(1));
            System.out.println("Major: " + matcher.group(2));
            System.out.println("Minor: " + matcher.group(3));
            System.out.println("Patch: " + matcher.group(4));
            System.out.println("Stability: " + matcher.group(5));
            
            System.out.println("\nGroup numbers:");
            for (int i = 0; i <=  matcher.groupCount(); i++) {
                System.out.println(i + ": " + matcher.group(i));
            }
        }
    }
}

此示例解析带有嵌套组的软件版本字符串。 外层组捕获完整的版本号,而内层组捕获组件。 组号由其开括号的位置分配。

来源

Java Matcher.group 文档

本教程涵盖了 Java Matcher.group 方法的基本方面。 从基本用法到高级技术,理解组对于使用 Java 中的正则表达式进行有效文本处理至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在该领域拥有多年的经验。 我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过 8 年的教学经验,致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程