ZetCode

Java MatchResult.groupCount 方法

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

MatchResult.groupCount 方法返回正则表达式模式中捕获组的数量。 它是 java.util.regex.MatchResult 接口的一部分。 此方法对于处理使用组的复杂正则表达式模式至关重要。

捕获组是正则表达式模式中用括号括起来的部分。 它们允许您提取匹配文本的特定部分。 groupCount 方法有助于确定模式中存在多少个这样的组。

MatchResult.groupCount 概述

groupCount 方法返回一个整数,表示模式中捕获组的数量。 此计数不包括特殊组 0,它始终表示整个匹配项。 该方法在 Matcher 对象和其他实现 MatchResult 的类上可用。

理解组计数在处理匹配项时至关重要,因为它有助于您了解可以访问多少个组。 可以使用索引从 1 到 groupCount() 的 group(int) 方法检索每个组。

基本 groupCount 示例

此示例演示了 groupCount 的基本用法,其中包含一个包含两个捕获组的简单模式。 我们将看到如何访问组计数和单个组。

BasicGroupCount.java
package com.zetcode;

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

public class BasicGroupCount {

    public static void main(String[] args) {
        String input = "John Doe, age 30";
        String regex = "(\\w+) (\\w+), age (\\d+)";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Total groups: " + matcher.groupCount());
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("First name: " + matcher.group(1));
            System.out.println("Last name: " + matcher.group(2));
            System.out.println("Age: " + matcher.group(3));
        }
    }
}

在此示例中,我们创建一个包含三个捕获组的模式。 groupCount 方法返回 3,与我们的三个带括号的组匹配。 然后,我们使用其索引 (1-3) 访问每个组,并使用索引 0 访问完整匹配项。

输出显示组 0 包含整个匹配项,而组 1-3 包含捕获的子字符串。 这演示了 groupCount 如何帮助浏览捕获的组。

groupCount 与嵌套组

此示例显示了 groupCount 如何与嵌套捕获组一起使用。 嵌套组会使模式更加复杂,但 groupCount 仍然可以准确地报告总数。

NestedGroups.java
package com.zetcode;

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

public class NestedGroups {

    public static void main(String[] args) {
        String input = "2023-05-15";
        String regex = "((\\d{4})-(\\d{2})-(\\d{2}))";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Total groups: " + matcher.groupCount());
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("Outer group: " + matcher.group(1));
            System.out.println("Year: " + matcher.group(2));
            System.out.println("Month: " + matcher.group(3));
            System.out.println("Day: " + matcher.group(4));
        }
    }
}

这里我们有一个带有嵌套组的日期模式。 外部组捕获整个日期,而内部组分别捕获年、月和日。 groupCount 返回 4,计算所有捕获组。

请注意,组 1 包含完整日期(与组 0 相同),而组 2-4 包含各个组件。 这表明嵌套组是如何从左到右按顺序计数的。

groupCount 与非捕获组

此示例演示了非捕获组(使用 (?:...))如何影响组计数。 非捕获组对于应用量词而不创建捕获组非常有用。

NonCapturingGroups.java
package com.zetcode;

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

public class NonCapturingGroups {

    public static void main(String[] args) {
        String input = "color or colour";
        String regex = "col(o?:u)r";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        while (matcher.find()) {
            System.out.println("\nMatch: " + matcher.group(0));
            System.out.println("Total groups: " + matcher.groupCount());
            System.out.println("Group 1: " + matcher.group(1));
        }
    }
}

在此模式中,我们有一个捕获组和一个非捕获组。 groupCount 返回 1,因为仅计算显式捕获组。 非捕获组不会增加计数。

输出显示,尽管模式中有两个带括号的表达式,但只有一个被计数并通过 group(1) 访问。 这演示了在不需要捕获时如何优化模式。

groupCount 与命名组

Java 支持使用 (?<name>...) 语法命名捕获组。 此示例显示了命名组如何影响 groupCount 以及如何访问它们。

NamedGroups.java
package com.zetcode;

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

public class NamedGroups {

    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("Total groups: " + matcher.groupCount());
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("Product (by name): " + matcher.group("product"));
            System.out.println("Product (by index): " + matcher.group(1));
            System.out.println("Price (by name): " + matcher.group("price"));
            System.out.println("Price (by index): " + matcher.group(2));
        }
    }
}

此示例使用两个命名组:“product”和“price”。 groupCount 返回 2,因为命名组仍然像往常一样计数。 可以通过名称或数字索引访问它们。

命名组使模式更具可读性和可维护性,尤其是在复杂模式下。 无论组是否命名,groupCount 方法的工作方式都相同。

groupCount 与零组

此示例显示了当模式没有捕获组时 groupCount 的行为。 它有助于理解组计数的基线情况。

ZeroGroups.java
package com.zetcode;

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

public class ZeroGroups {

    public static void main(String[] args) {
        String input = "Simple text matching";
        String regex = "[A-Za-z ]+";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Total groups: " + matcher.groupCount());
            System.out.println("Full match: " + matcher.group(0));
            
            // Attempting to access group 1 would throw IndexOutOfBoundsException
            try {
                System.out.println("Group 1: " + matcher.group(1));
            } catch (IndexOutOfBoundsException e) {
                System.out.println("Cannot access group 1: " + e.getMessage());
            }
        }
    }
}

这里我们有一个没有捕获组的模式。 groupCount 方法返回 0,表示除了组 0(完整匹配)之外,没有其他组可以访问。 尝试访问组 1 会引发异常。

这表明 groupCount 准确地反映了模式何时没有捕获组。 在通过索引访问组之前,检查此项始终是安全的。

groupCount 与交替

此示例探讨了交替(使用 | 运算符)如何影响组计数。 我们将看到交替的不同分支如何具有不同数量的组。

AlternationGroups.java
package com.zetcode;

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

public class AlternationGroups {

    public static void main(String[] args) {
        String input1 = "Date: 2023-05-15";
        String input2 = "Timestamp: 202305151200";
        String regex = "(Date: (\\d{4}-\\d{2}-\\d{2}))|(Timestamp: (\\d{12}))";
        
        Pattern pattern = Pattern.compile(regex);
        
        // Test first pattern branch
        Matcher matcher1 = pattern.matcher(input1);
        if (matcher1.find()) {
            System.out.println("Input1 groups: " + matcher1.groupCount());
            System.out.println("Full match: " + matcher1.group(0));
            System.out.println("Date group: " + matcher1.group(1));
            System.out.println("Date value: " + matcher1.group(2));
        }
        
        // Test second pattern branch
        Matcher matcher2 = pattern.matcher(input2);
        if (matcher2.find()) {
            System.out.println("\nInput2 groups: " + matcher2.groupCount());
            System.out.println("Full match: " + matcher2.group(0));
            System.out.println("Timestamp group: " + matcher2.group(3));
            System.out.println("Timestamp value: " + matcher2.group(4));
        }
    }
}

此模式具有交替,每个分支中的组数不同。 groupCount 返回 4,表示整个模式中捕获组的总数,无论哪个分支匹配。

当第一个分支匹配时,组 1 和 2 包含值,而组 3 和 4 为 null。 相反,当第二个分支匹配时,组 3 和 4 包含值。 这显示了 groupCount 如何报告最大可能的组数。

groupCount 在替换操作中

最后一个示例演示了在字符串替换操作的上下文中使用 groupCount。 我们将看到组计数如何影响替换模式。

ReplacementGroups.java
package com.zetcode;

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

public class ReplacementGroups {

    public static void main(String[] args) {
        String input = "Name: John Doe, Phone: (123) 456-7890";
        String regex = "Name: (\\w+) (\\w+), Phone: \\((\\d{3})\\) (\\d{3})-(\\d{4})";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        if (matcher.find()) {
            System.out.println("Total groups: " + matcher.groupCount());
            
            // Simple replacement using group references
            String result1 = matcher.replaceAll("Contact: $1 $2, Phone: ($3) $4-$5");
            System.out.println("\nReplacement 1: " + result1);
            
            // More complex replacement using group count
            StringBuilder sb = new StringBuilder();
            for (int i = 1; i <=  matcher.groupCount(); i++) {
                sb.append("Group ").append(i).append(": [")
                  .append(matcher.group(i)).append("] ");
            }
            String result2 = matcher.replaceAll(sb.toString());
            System.out.println("Replacement 2: " + result2);
        }
    }
}

此示例显示了使用组引用的两个替换操作。 groupCount 帮助我们了解可以在替换中引用多少个组。 第一个替换使用固定的组引用,而第二个替换基于组计数动态构建替换。

输出演示了替换字符串中的组引用($1、$2 等)如何对应于捕获的组。 了解组计数对于创建正确的替换模式至关重要。

来源

Java MatchResult 文档

在本文中,我们通过各种示例彻底探讨了 MatchResult.groupCount 方法。 理解组计数对于 Java 中有效的正则表达式处理至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的敬业程序员。 我于 2007 年开始撰写编程文章,至今已撰写了 1,400 多篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程