Pattern 与 Matcher 的分工
java.util.regex 把正则拆成两个对象:Pattern 是编译后的模式(不可变、线程安全,适合做成 static final 复用),Matcher 是一次匹配的游标(持有位置与分组状态,线程不安全,必须每次新建)。引擎是回溯式 NFA,因此支持环视、反向引用、占有量词等 PCRE 常见特性,也继承了灾难性回溯的风险。
基本信息
| 适用平台 | JDK 8 及以上(本项目以 8/11/17 为主流) |
|---|---|
| 包名 | java.util.regex.Pattern / Matcher |
| 引擎类型 | 回溯式 NFA,非 RE2 线性引擎 |
| 支持特性 | 环视、反向引用、命名组 (?<name>)、\p{...} 属性 |
| 字面量转义 | Java 源码里 \d 要写成 "\\d";或用 Pattern.quote() 包住整段 |
| 线程安全 | Pattern 安全,Matcher 不安全 |
典型使用场景
- 日志与文本解析:按固定格式抽取字段,如时间戳、等级、trace id
- 输入校验:手机号、日期、编码等格式的整串匹配(matches 而非 find)
- 批量替换:按规则改写配置文本,配合 $1 分组引用回填
- 分词或切分:按复杂分隔规则 split(比 String.split 更可控)
- 结构性查找:从大文本里定位所有 URL、key=value 片段
最小可用示例
最小可用示例
Pattern P = Pattern.compile("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s+(\\S+)"); // 预编译一次,复用
Matcher m = P.matcher("2026-10-17 ERROR disk.full"); // 每次匹配新建 Matcher
while (m.find()) { // find:在串中顺序查找下一处
System.out.println(m.group(1) + "/" + m.group(2)); // group(1) 取第一个捕获组
System.out.println(m.start() + "-" + m.end()); // 记录命中位置,便于截取原文
}
boolean ok = P.matcher("2026-10-17").matches(); // matches:整串必须完全符合
String q = Pattern.quote("a.b(c)"); // 需要按字面匹配时就别手写转义常用方法语义对照
| 方法 | 含义 | 常见误用 |
|---|---|---|
| matches() | 整串匹配,等价两边加锚定 | 想找子串却用了它,结果恒为 false |
| find() | 从当前位置起查找下一处命中 | 忘记循环前先判 find() 就直接调用 group() |
| lookingAt() | 只要从串开头匹配即可 | 与 matches 混淆,导致尾部多余字符被放过 |
| group(n) | 取第 n 个捕获组(0 为整体) | 组未参与匹配时返回 null,直接拼接会变 "null" |
| replaceAll / replaceFirst | 按组引用替换,$1 表示第一组 | 替换文本里的 $ 与 \ 需转义,否则抛异常或语义错 |
| split() | 按模式切分 | limit 参数不传会把尾部空串丢掉 |
Java 9 起 Matcher 增加了 results() 与 replaceAll(Function) 等流式与函数式接口,处理多命中时更直观;命名组(Pattern 中写 (?<y>...))可用 group("y") 取值,可读性远好于纯数字下标。版本能力以官方 javadoc 为准。
嵌套量词(如 (a+)+$)在长串上会指数级回溯,线上表现为 CPU 打满或抛 StackOverflowError。规避手段:改写为原子组/占有量词、限制输入长度、必要时给匹配任务加超时与中断。正则跑在处理用户输入的关键路径上时必须先限长度。
默认字符类 \w \d 在 Java 里只匹配 ASCII,要按 Unicode 语义匹配需加 Pattern.UNICODE_CHARACTER_CLASS 标志;比较新版本中该标志对 \w、\b 等的影响要实测确认。