0Pricing
Java Academy · 课时

捕获组

提取匹配的子字符串

捕获组 是 CoddyKit 上的免费 Java Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

什么是捕获组

正则表达式中的圆括号 ( ) 会创建捕获组。匹配完成后,您可以分别提取每个组的文本,这非常适合解析结构化数据。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\d+)-(\\d+)").matcher("42-99");
        if (m.find()) {
            System.out.println(m.group(1));
            System.out.println(m.group(2));
        }
    }
}

组 0 是整个匹配项

group(0)(或 group())返回完整的匹配文本。编号组从 1 开始。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\d+)px").matcher("width: 24px");
        if (m.find()) {
            System.out.println(m.group(0));
            System.out.println(m.group(1));
        }
    }
}

统计捕获组

groupCount() 会报告模式中捕获组的数量(不包括组 0)。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})").matcher("2026-05-30");
        if (m.find()) System.out.println(m.groupCount());
    }
}

解析日期

捕获组可以轻松地将格式化的值拆分成多个部分。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})").matcher("2026-05-30");
        if (m.matches()) {
            System.out.println("year=" + m.group(1));
            System.out.println("month=" + m.group(2));
            System.out.println("day=" + m.group(3));
        }
    }
}

命名组

使用 (?<name>...) 为组命名,然后按名称获取它。这样可以大幅提升模式的可读性。

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

public class Main {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("(?<user>\\w+)@(?<host>\\w+\\.\\w+)");
        Matcher m = p.matcher("alice@example.com");
        if (m.find()) {
            System.out.println(m.group("user"));
            System.out.println(m.group("host"));
        }
    }
}

组的边界

start(n) 和 end(n) 会给出特定组在输入中的索引范围。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\d+)").matcher("abc123");
        if (m.find()) {
            System.out.println(m.start(1) + " to " + m.end(1));
        }
    }
}

非捕获组

使用 (?:...) 可以为交替匹配或量词进行分组,且不会创建编号捕获组。这样可以让组编号更有意义。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(?:Mr|Ms)\\.? (\\w+)").matcher("Ms. Smith");
        if (m.find()) System.out.println(m.group(1));
    }
}

可选组可能为 null

如果某个组是可选的,并且没有参与匹配,group(n) 就会返回 null。请始终处理这种情况。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\d+)(px)?").matcher("50");
        if (m.matches()) {
            System.out.println(m.group(1));
            System.out.println(m.group(2));
        }
    }
}

使用组遍历匹配项

将循环中的 find 与组提取结合起来,可以从较大的文本中提取结构化标记。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\w+)=(\\d+)").matcher("a=1 b=2 c=3");
        while (m.find()) {
            System.out.println(m.group(1) + " -> " + m.group(2));
        }
    }
}

模式中的反向引用

在正则表达式中,\1 会匹配之前某个组捕获的相同文本。这可用于检测重复内容,例如连续出现两次的单词。

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

public class Main {
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(\\w+) \\1").matcher("the the cat");
        System.out.println(m.find());
        System.out.println(m.group(1));
    }
}

将捕获内容存入记录

一种清晰的模式是:进行匹配、提取各组,然后构建一个小型对象。这里使用的是记录类。

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

public class Main {
    record Point(int x, int y) {}

    public static void main(String[] args) {
        Matcher m = Pattern.compile("\\((\\d+),(\\d+)\\)").matcher("(3,7)");
        if (m.matches()) {
            Point p = new Point(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)));
            System.out.println(p);
        }
    }
}

快速检查

成功匹配后,group(0) 会返回什么?

回顾

您已经学习了如何提取匹配到的子字符串:

  • 圆括号会创建编号组;group(0) 是完整匹配项,1 及更大的编号表示捕获组。
  • (?<name>...) 会创建命名组,并通过 group("name") 读取。
  • (?:...) 可以分组但不会进行捕获。
  • 可选组可能为 null;\1 会反向引用之前的组。

常见问题解答

「捕获组」课时是免费的吗?

是的 — 「捕获组」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「捕获组」这节课中我会学到什么?

提取匹配的子字符串 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「捕获组」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 编译正则表达式
  2. 查找与匹配
  3. 捕获组
  4. 使用正则替换
← 返回 Java Academy