443. Java 正则表达式 - 分组、字符类与量词的结合 & 三种量词模式

文章目录

  • [443. Java 正则表达式 - 分组、字符类与量词的结合 & 三种量词模式](#443. Java 正则表达式 - 分组、字符类与量词的结合 & 三种量词模式)
    • [1. Capturing Groups + Quantifiers 🧩](#1. Capturing Groups + Quantifiers 🧩)
      • [示例对比 🧪](#示例对比 🧪)
    • [2. Character Classes + Quantifiers 🎲](#2. Character Classes + Quantifiers 🎲)
      • [示例对比 🧪](#示例对比 🧪)
    • [3. 三种量词模式的区别 🥊](#3. 三种量词模式的区别 🥊)
      • 示例:输入串
        • [3.1 Greedy(贪婪)](#3.1 Greedy(贪婪))
        • [3.2 Reluctant(勉强)](#3.2 Reluctant(勉强))
        • [3.3 Possessive(独占)](#3.3 Possessive(独占))
    • [4. 使用建议 💡](#4. 使用建议 💡)
    • [5. 课堂练习 🎤](#5. 课堂练习 🎤)

443. Java 正则表达式 - 分组、字符类与量词的结合 & 三种量词模式

大家好 🚀,在上节我们讲了量词 ? * + {n,m},今天我们要升级一下:

👉 看看量词如何和 分组 (Capturing Groups)字符类 (Character Classes) 搭配使用,

以及 贪婪 (Greedy)勉强 (Reluctant)独占 (Possessive) 三种量词模式的区别。


1. Capturing Groups + Quantifiers 🧩

一个量词默认只能修饰 前面的一个字符

比如:

java 复制代码
abc+

含义是:

  • 一个 a,接着一个 b,最后一个或多个 c
    ❌ 注意:它不是 "abc 一组,重复多次"。

如果我们希望量词作用于 整个单词/片段,必须加括号:

java 复制代码
(abc)+

意思就是:整个 "abc" 作为一个整体,出现 1 次或多次。


示例对比 🧪

例1

java 复制代码
(dog){3}

输入:dogdogdogdogdogdog

  • 匹配到 "dogdogdog"(前 3 次 dog)
  • 继续往后,又匹配到 "dogdogdog"(第 4~6 次 dog)

✅ 量词 {3} 作用于整个组 (dog)


例2

java 复制代码
dog{3}

输入:dogdogdogdogdogdog

  • ❌ 没有任何匹配
    因为这里 {3} 只修饰 "g",意思是:
    do + "g" 重复 3 次 → 期望匹配 "doggg"

👉 课堂提问

如果我写 (ab){2},能匹配 "abab" 吗?(✅ 是的)

如果我写 ab{2},能匹配 "abb" 吗?(✅ 是的)


2. Character Classes + Quantifiers 🎲

量词同样可以修饰 字符类

java 复制代码
[abc]{3}

含义是:从 abc 中任选一个字符,重复 3 次。


示例对比 🧪

例1

java 复制代码
[abc]{3}

输入:abccabaaaccbbbc

匹配结果:

  • "abc"
  • "cab"
  • "aaa"
  • "ccb"
  • "bbc"

例2

java 复制代码
abc{3}

输入:abccabaaaccbbbc

  • ❌ 无匹配
    因为这里 {3} 只修饰 "c",意思是:ab + "c" 连续 3 次 → "abccc"

👉 课堂总结

  • (abc)+ → 整个 "abc" 重复
  • [abc]+"a""b""c",随机重复
  • abc+ → 只有 "c" 重复

3. 三种量词模式的区别 🥊

我们之前用过的量词,其实分三种模式:

  • Greedy 贪婪(默认)
  • Reluctant 勉强 (加 ?
  • Possessive 独占 (加 +

示例:输入串

java 复制代码
xfooxxxxxxfoo
3.1 Greedy(贪婪)
java 复制代码
.*foo

结果:

  • 匹配 "xfooxxxxxxfoo"(整个字符串)

解释:

.* 先吃掉整串 → 发现 "foo" 没地方了 → 回退,直到找到最后一个 "foo"

👉 贪婪模式 = 先吃光,再回吐


3.2 Reluctant(勉强)
java 复制代码
.*?foo

结果:

  • 第一次匹配 "xfoo"(0~4)
  • 第二次匹配 "xxxxxxfoo"(4~13)

解释:

.*? 先什么都不吃 → 发现 "foo" 没匹配 → 慢慢吃 → 直到 "foo" 出现。

👉 勉强模式 = 先饿着,能不吃就不吃


3.3 Possessive(独占)
java 复制代码
.*+foo

结果:

  • ❌ 没有匹配

解释:

.*+ 一口吃光,不吐 → "foo" 已经没地方匹配了。

👉 独占模式 = 霸占到底,绝不回吐


4. 使用建议 💡

  • Greedy:默认选择,常见场景

  • Reluctant :当需要 最短匹配 时用,比如提取 HTML 标签内容

    java 复制代码
    <.*?>   // 最小化匹配 <p> ... </p>
  • Possessive:性能优化用,避免回溯浪费时间(比如匹配超长字符串时)


5. 课堂练习 🎤

  1. 写一个正则,匹配 "cat""dog",重复 2 次。
    👉 提示:(cat|dog){2}
  2. 用勉强量词,提取字符串 <div>hello</div> 中的 "hello"
    👉 提示:<.*?>(.*?)<.*?>
  3. 输入:aaaaab,正则 a++b 能匹配吗?为什么?
    👉 ❌ 不行,因为 a++ 吃掉所有 a,不回吐,后面就没 b 可匹配。