444. Java 正则表达式 - 捕获组与反向引用

文章目录

  • [444. Java 正则表达式 - 捕获组与反向引用](#444. Java 正则表达式 - 捕获组与反向引用)
    • [1. 什么是捕获组? 🧩](#1. 什么是捕获组? 🧩)
    • [2. 捕获组的编号规则 🔢](#2. 捕获组的编号规则 🔢)
      • [在 Java 中如何查看捕获组?](#在 Java 中如何查看捕获组?)
      • [示例 🧪](#示例 🧪)
    • [3. 反向引用 (Backreferences) 🔄](#3. 反向引用 (Backreferences) 🔄)
      • [示例 1:匹配连续重复的数字](#示例 1:匹配连续重复的数字)
      • [示例 2:匹配相同单词](#示例 2:匹配相同单词)
      • [示例 3:嵌套组也能反向引用](#示例 3:嵌套组也能反向引用)
    • [4. 非捕获组 (Non-Capturing Groups) 🙅‍♂️](#4. 非捕获组 (Non-Capturing Groups) 🙅‍♂️)
    • [5. 小结 ✨](#5. 小结 ✨)
    • [6. 课堂练习 🎤](#6. 课堂练习 🎤)

444. Java 正则表达式 - 捕获组与反向引用

大家好 🚀,今天我们继续深入学习正则表达式,重点是 捕获组 (Capturing Groups)反向引用 (Backreferences)


1. 什么是捕获组? 🧩

捕获组的作用:

👉 把一串字符 当作一个整体 来处理。

写法:用 () 括起来。

java 复制代码
(dog)

这就表示一个组,包含 "dog" 三个字符。

匹配时,Java 会把这个组匹配到的内容保存起来,方便后面通过 反向引用 重新使用。


2. 捕获组的编号规则 🔢

捕获组是从 左到右 数开括号 ( 的顺序来编号的。

例如:

java 复制代码
((A)(B(C)))

这里有 4 个捕获组:

1️⃣ ((A)(B(C))) → 最外层大括号

2️⃣ (A)

3️⃣ (B(C))

4️⃣ (C)


在 Java 中如何查看捕获组?

Matcher 提供了一些方法:

java 复制代码
matcher.groupCount();   // 捕获组的总数(不包括 group 0)
matcher.group(0);       // 整个正则匹配到的内容
matcher.group(1);       // 第1个捕获组
matcher.start(1);       // 捕获组1的起始位置
matcher.end(1);         // 捕获组1的结束位置

👉 注意

  • group(0) → 总是代表整个正则表达式的匹配结果
  • group(1) ~ group(n) → 依次代表括号里的捕获组

示例 🧪

java 复制代码
import java.util.regex.*;

public class CapturingGroupsDemo {
    public static void main(String[] args) {
        String input = "abc123xyz";
        String regex = "(abc)(\\d+)(xyz)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        if (matcher.find()) {
            System.out.println("Group count = " + matcher.groupCount()); 
            System.out.println("Group 0 = " + matcher.group(0)); // abc123xyz
            System.out.println("Group 1 = " + matcher.group(1)); // abc
            System.out.println("Group 2 = " + matcher.group(2)); // 123
            System.out.println("Group 3 = " + matcher.group(3)); // xyz
        }
    }
}

运行结果:

java 复制代码
Group count = 3
Group 0 = abc123xyz
Group 1 = abc
Group 2 = 123
Group 3 = xyz

3. 反向引用 (Backreferences) 🔄

捕获组匹配的内容会被保存,之后可以通过 \1, \2 ... 来引用。

  • \1 → 引用第1个捕获组
  • \2 → 引用第2个捕获组
  • 依此类推

示例 1:匹配连续重复的数字

java 复制代码
(\d\d)\1

含义:

  • (\d\d) → 匹配两个数字(第1组)
  • \1 → 再次匹配刚刚捕获到的两个数字

测试:

java 复制代码
输入:1212   ✅ 匹配
输入:1234   ❌ 不匹配

示例 2:匹配相同单词

java 复制代码
(\w+)\s\1

含义:

  • (\w+) → 匹配一个单词(第1组)
  • \s → 匹配一个空格
  • \1 → 再匹配前面那个单词

测试:

java 复制代码
输入:hello hello   ✅ 匹配
输入:hello world   ❌ 不匹配

示例 3:嵌套组也能反向引用

java 复制代码
(A(B(C)))
  • group(1) = ABC
  • group(2) = BC
  • group(3) = C

如果写 (A(B(C)))\2

→ 先匹配 "ABC",然后再匹配 "BC"


4. 非捕获组 (Non-Capturing Groups) 🙅‍♂️

有时候我们只想用括号分组,但不想保存内容,这时可以用:

java 复制代码
(?:...)

示例:

java 复制代码
(?:dog|cat){2}

表示 "dog""cat",重复两次,但不会保存组内容。


5. 小结 ✨

  • () → 捕获组,自动编号
  • group(0) → 整体匹配
  • group(n) → 第 n 个捕获组
  • \n → 反向引用第 n 个捕获组
  • (?:...) → 非捕获组

6. 课堂练习 🎤

  1. 写一个正则,匹配 "abab" 这种模式(重复的 "ab")。
    👉 提示:(ab)\1
  2. 匹配重复单词(如 "bye bye")。
    👉 提示:(\w+)\s\1
  3. 用非捕获组写一个正则,匹配 "dogdogcatcat"
    👉 提示:(?:dog|cat){2,}