核心方法概览
| 方法 | 来源 | 描述 | 示例 |
|---|---|---|---|
replaceAll(String regex, String replacement) |
String |
替换所有匹配正则表达式的子串为 replacement。 |
"abc123".replaceAll("\\d", "X") -> "abcXXX" |
replaceFirst(String regex, String replacement) |
String |
替换第一个匹配正则表达式的子串为 replacement。 |
"abc123".replaceFirst("\\d", "X") -> "abcX23" |
appendReplacement(StringBuffer sb, String replacement) |
Matcher |
替换当前匹配项,并将结果追加到 StringBuffer,同时移动匹配位置。 |
用于复杂的、循环替换的场景。 |
appendTail(StringBuffer sb) |
Matcher |
将输入字符串中剩余未处理的部分追加到 StringBuffer。 |
通常在 appendReplacement 循环之后调用。 |
String.replaceAll() 和 replaceFirst()
这是最简单、最常用的方法,适用于大多数替换场景。

replaceAll(String regex, String replacement)
替换所有匹配的子串。
示例 1:简单的数字替换
String str = "我的电话是 138-1234-5678,备用电话是 139-8765-4321。";
// 将所有数字替换为 "X"
String result = str.replaceAll("\\d", "X");
System.out.println(result);
// 输出: 我的电话是 XXX-XXXX-XXXX,备用电话是 XXX-XXXX-XXXX。
\\d是一个正则表达式,匹配任意一个数字字符。
示例 2:替换特定格式的字符串
String str = "订单号: ORD-2025-001, 发货单: SHP-2025-002, 无效单号: ABC-2025-003";
// 替换所有 "ORD-" 或 "SHP-" 开头的订单号
String result = str.replaceAll("(ORD|SHP)-\\d+-\\d+", "已处理");
System.out.println(result);
// 输出: 订单号: 已处理, 发货单: 已处理, 无效单号: ABC-2025-003
(ORD|SHP)匹配 "ORD" 或 "SHP"。\\d+匹配一个或多个数字。
replaceFirst(String regex, String replacement)
只替换第一个匹配的子串。

String str = "apple banana apple orange";
// 只替换第一个 "apple"
String result = str.replaceFirst("apple", "grape");
System.out.println(result);
// 输出: grape banana apple orange
Matcher 类的替换方法 (appendReplacement & appendTail)
当替换逻辑非常复杂时(替换内容依赖于匹配到的内容本身),使用 String.replaceAll() 会很困难,这时就需要 java.util.regex.Matcher 类。
Matcher 提供了更底层的、基于迭代和缓冲区的替换机制。
工作流程:
- 创建一个
Pattern对象(正则表达式编译后的形式)。 - 用
pattern.matcher(str)创建一个Matcher对象。 - 创建一个
StringBuffer来存储结果。 - 在一个循环中调用
matcher.find()来查找下一个匹配项。 - 对每个匹配项,调用
matcher.appendReplacement(sb, replacement)进行替换并追加到StringBuffer。 - 循环结束后,调用
matcher.appendTail(sb)将剩余部分追加到StringBuffer。
示例:反向引用替换
这是 Matcher 最强大的功能之一,你可以在替换字符串 replacement 中引用正则表达式中的捕获组。

捕获组是用 括起来的子表达式,在替换字符串中,用 $n 来引用第 n 个捕获组。
示例 1:交换姓名的格式
import java.util.regex.*;
String str = "姓名: 张三, 年龄: 30; 姓名: 李四, 年龄: 25;";
// 目标: 将 "张三, 30" 变成 "30, 张三"
// 正则表达式: 匹配 "姓名: (.*?), 年龄: (.*?);"
// (.*?) 是非贪婪匹配,匹配尽可能少的字符
Pattern pattern = Pattern.compile("姓名: (.*?), 年龄: (.*?);");
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// $2 引用第二个捕获组 (年龄)
// $1 引用第一个捕获组 (姓名)
// Matcher.quoteReplacement() 是一个好习惯,可以防止 replacement 中的 $ 被误认为是反向引用
matcher.appendReplacement(sb, "年龄: " + matcher.group(2) + ", 姓名: " + matcher.group(1) + ";");
}
// 将最后未匹配的部分(如果有)追加到 sb
matcher.appendTail(sb);
System.out.println(sb.toString());
// 输出: 年龄: 30, 姓名: 张三; 年龄: 25, 姓名: 李四;
示例 2:在匹配的文本两侧添加标记
import java.util.regex.*;
String str = "重要信息:Java 17 发布了,次要信息:Python 也很流行。";
Pattern pattern = Pattern.compile("(.{4})信息:(.+?)。"); // 匹配 "xx信息:内容。"
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// 在捕获组内容前后添加 <mark> 标签
String replacement = "<mark>" + matcher.group(1) + "信息:</mark>" + matcher.group(2) + "。";
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);
System.out.println(sb.toString());
// 输出: 重要信息:<mark>重要信息:</mark>Java 17 发布了,次要信息:<mark>次要信息:</mark>Python 也很流行。
- 注意:这里
$n的写法在appendReplacement中不能直接使用,因为它会把$n当作字面字符,必须通过matcher.group(n)来获取捕获组的实际内容,然后拼接到替换字符串中。
替换字符串中的特殊字符 ( 和 \)
在 replaceAll 和 appendReplacement 的 replacement 参数中, 是一个特殊字符,用于反向引用。
$1,$2, ...: 引用第 1, 2, ... 个捕获组。$&: 代表整个匹配的文本。- 代表匹配文本之前的字符串。
- 代表匹配文本之后的字符串。
示例:使用 $&
String str = "hello world";
// 在每个单词前后加上引号
String result = str.replaceAll("\\b\\w+\\b", "'$&'");
System.out.println(result);
// 输出: 'hello' 'world'
\\b是单词边界,\\w+是一个或多个单词字符。
如何转义 ?
如果你的 replacement 字符串中恰好需要包含一个 字符,你需要用 \\ 对其进行转义。
String str = "price is $100";
// 想在每个数字前加上 "USD "
String result = str.replaceAll("\\d", "USD \\$0"); // \\$ 转义 $,\\0 引用整个匹配项(即那个数字)
System.out.println(result);
// 输出: price is USD $1USD $0USD $0
$0在 Java 中是无效的,它代表整个匹配项,但 Java 中通常用$&,这里\\d匹配一个数字,$&就是那个数字本身。USD $&会变成USD 1。- 为了匹配
100这个整体,可以这样:String result2 = str.replaceAll("\\d+", "USD $$&"); // 使用 $$ 来转义,得到字面 $ System.out.println(result2); // 输出: price is USD $100
总结与最佳实践
- 简单替换:优先使用
String.replaceAll()和String.replaceFirst(),它们代码简洁,性能良好。 - 复杂替换:当替换逻辑需要依赖捕获组内容、或在循环中处理多个匹配项时,使用
Matcher的appendReplacement()和appendTail()方法。 - 反向引用:
$n用于在replacement字符串中引用捕获组,这是非常强大的功能。 - 转义特殊字符:
replacement中需要包含 或\,记得使用\\进行转义,在Matcher方法中,直接拼接matcher.group(n)是更安全的方式。 - 性能:如果需要对大量字符串进行相同的正则操作,预先编译
Pattern对象 (Pattern.compile()) 然后重用Matcher对象,会比每次都调用String.replaceAll()更高效。
希望这份详细的解释能帮助你掌握 Java 中的正则表达式替换!
