源本科技 | 码上会

什么是正则表达式

2025/12/26
36
0

学习目标

  • 掌握 java.util.regex 包中 PatternMatcher 的核心用法

  • 熟练运用 字符类、量词、预定义模式 构建有效正则表达式

  • 能区分 全匹配(matches)部分查找(find) 的使用场景

  • 运用正则解决实际问题:验证、提取、替换、分割文本


正则表达式简介

正则表达式(Regular Expressions,简称 Regex)是一种用于描述字符串模式的强大工具。在 Java 中,它被广泛应用于:

  • ✉️ 邮箱、手机号、身份证号格式校验

  • 🔒 密码强度检测

  • 📊 日志解析与数据提取

  • ✂️ 文本清洗与批量替换

💡 核心优势:用简短的模式规则替代复杂的字符串逻辑判断。


java.util.regex 包核心类

Java 通过 java.util.regex 包提供正则支持,主要包含三个类:

作用

Pattern

编译正则表达式,生成可复用的模式对象

Matcher

对输入字符串执行匹配、查找、替换等操作

PatternSyntaxException

正则语法错误时抛出的异常


Pattern 类

编译正则模式

常用方法

// 1. 编译正则(推荐复用)
Pattern p = Pattern.compile("\\d{4}");

// 2. 创建匹配器
Matcher m = p.matcher("2025年");

// 3. 静态全匹配(内部仍会编译,不建议频繁调用)
boolean isMatch = Pattern.matches("\\d+", "123");

示例:基础匹配验证

import java.util.regex.Pattern;

public class CoderHub {
    public static void main(String[] args) {
        // 模式: 以 "hello" 开头,后接任意字符
        System.out.println(Pattern.matches("hello.*", "helloworld")); // true
        
        // 模式: "hello" + 至少一个数字(注意:不能有字母!)
        System.out.println(Pattern.matches("hello[0-9]+", "hello12s"));   // false(末尾有's')
    }
}

📌 Pattern.matches() 要求整个字符串完全匹配正则。


Matcher 类

执行匹配操作

核心方法

方法

功能

find()

查找下一个匹配项(支持多次调用)

matches()

判断整个输入是否匹配(等价于 ^...$

start() / end()

获取当前匹配的起止索引(end() 返回的是后一位

group()

获取当前匹配的子串

replaceAll(String)

替换所有匹配项

split(CharSequence)

按模式分割字符串

示例:查找所有匹配位置

import java.util.regex.*;

public class RegexDemo {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("hello");
        Matcher m = p.matcher("helloworld.org");

        while (m.find()) {
            System.out.println("匹配位置: " + m.start() + " 到 " + (m.end() - 1));
        }
    }
}

输出

匹配位置: 0 到 4

✅ 使用 find() 可找到多个匹配项,而 matches() 只能判断整体是否匹配。


正则语法

字符类

表达式

含义

示例

[abc]

匹配 a、b 或 c

[aeiou] → 元音字母

[^abc]

不匹配 a、b、c

[^0-9] → 非数字

[a-z]

小写字母范围

[A-Za-z] → 所有英文字母

[a-f[m-t]]

并集:a-f 或 m-t

[a-c[x-z]] → a,b,c,x,y,z

[a-z&&[^m-p]]

交集:a-z 但排除 m-p

→ a-l, q-z

System.out.println(Pattern.matches("[a-z]", "g"));      // true(单个小写字母)
System.out.println(Pattern.matches("[a-zA-Z]", "Gfg")); // false(要求整个字符串是单个字母!)

⚠️ 注意:Pattern.matches() 要求整个字符串符合模式,"Gfg" 长度为 3,不匹配 [a-zA-Z](仅匹配单字符)。


量词

量词

含义

示例匹配

X?

0 次或 1 次

"colou?r" → color, colour

X+

1 次或多次

"\\d+" → 1, 123, 9999

X*

0 次或多次

"a*" → "","a","aaa"

X{n}

恰好 n 次

"\\d{4}" → 2025

X{n,}

至少 n 次

"\\d{2,}" → 12, 123, ...

X{n,m}

n 到 m 次

"a{2,4}" → aa, aaa, aaaa

System.out.println(Pattern.matches("\\d{4}", "1234")); // true(4位数字)
System.out.println(Pattern.matches("\\d{4}", "123"));  // false(不足4位)
System.out.println(Pattern.matches("[a-z]+", "hello")); // true(至少1个小写字母)
System.out.println(Pattern.matches("[a-z]+", ""));      // false(空串不满足"+")
System.out.println(Pattern.matches("a*", "aaaa"));      // true(*允许0次或多次)

预定义字符类

模式

等价写法

含义

.

任意字符(除换行符)

\d

[0-9]

数字

\D

[^0-9]

非数字

\s

[ \t\n\x0B\f\r]

空白字符

\S

[^ \t\n\x0B\f\r]

非空白字符

\w

[a-zA-Z_0-9]

单词字符(字母、数字、下划线)

\W

[^\w]

非单词字符

\b

单词边界(如空格、标点前后)

\B

非单词边界

🔑 注意:在 Java 字符串中,反斜杠需转义,故写作 "\\d" 而非 "\d"

System.out.println(Pattern.matches("\\d+", "1234")); // true
System.out.println(Pattern.matches("\\D+", "1234")); // false(全是数字)
System.out.println(Pattern.matches("\\D+", "Gfg"));  // true(无数字)
System.out.println(Pattern.matches("\\S+", "gfg"));  // true(无空白)

实战应用场景

场景 1:邮箱格式验证

String email = "user@coderhub.com";
boolean isValid = email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");

场景 2:提取所有数字

String text = "订单号: 12345, 金额: 99.99元";
Pattern p = Pattern.compile("\\d+\\.?\\d*");
Matcher m = p.matcher(text);
while (m.find()) {
    System.out.println("提取: " + m.group()); // 12345, 99.99
}

场景 3:敏感词替换

String content = "这个产品太垃圾了!";
String safe = content.replaceAll("垃圾", "**");
// 结果: "这个产品太**了!"

场景 4:按分隔符分割

String log = "2025-12-26 INFO User login";
String[] parts = log.split("\\s+"); // 按一个或多个空白符分割
// 结果: ["2025-12-26", "INFO", "User", "login"]

关键注意事项

  1. 性能优化

    • 频繁使用的正则应预先编译Pattern.compile()),避免重复解析。

    • 避免在循环内调用 Pattern.matches()

  2. 匹配模式区别

    • Pattern.matches(regex, input) ≡ 整个字符串必须匹配(隐含 ^...$

    • Matcher.find() → 查找任意位置的匹配子串

  3. 转义字符

    • Java 字符串中 \ 需写成 \\,如 "\\d" 表示正则中的 \d

    • 特殊字符(如 .*?)在正则中有特殊含义,匹配字面值需转义:\\.

  4. 贪婪 vs 懒惰

    • 默认量词是贪婪的(尽可能多匹配),可用 ? 变懒惰:.*?


重点总结

  • Pattern + Matcher 是正则操作的标准组合

  • 字符类 [...] 定义字符集合,量词 *+?{n} 控制重复次数

  • 预定义模式\d, \w, \s)极大简化常见匹配

  • 全匹配matches)用于验证,查找find)用于提取

  • 正则虽强大,但过度复杂的表达式会降低可读性,必要时拆解逻辑

最佳实践

  • 对于简单验证(如非空、固定前缀),优先使用 String 自带方法(startsWith, contains);

  • 对于结构化文本处理,正则是不可替代的利器。


思考题

  1. 编写一个正则表达式,匹配中国大陆手机号(11 位,以 1 开头),并用 Matcher 提取文本中的所有手机号。

  2. 为什么 Pattern.matches(".", "ab") 返回 false?如何修改才能匹配任意长度的非空字符串?

  3. 在日志分析中,如何提取如 [ERROR] 2025-12-26 18:00:00 - Database connection failed 中的时间戳和错误信息?