String.replaceAll()
String.replaceAll() 是 Java String 类的一个方法,用于替换字符串中所有匹配正则表达式的子串。

方法签名
public String replaceAll(String regex, String replacement)
regex(正则表达式): 你要查找的模式的字符串描述。这里的关键是,它是一个正则表达式,而不仅仅是普通文本。replacement(替换字符串): 用来替换匹配项的字符串,这个字符串中可以使用特殊的“反向引用”语法。
工作原理与示例
replaceAll 会遍历整个字符串,找到所有与 regex 匹配的子串,然后用 replacement 字符串替换它们。
示例 1:简单的文本替换
即使不使用正则表达式的特性,replaceAll 也可以像 replace 一样工作。
String str = "Hello World, Hello Java";
// 将所有的 "Hello" 替换为 "Hi"
String result = str.replaceAll("Hello", "Hi");
System.out.println(result); // 输出: Hi World, Hi Java
示例 2:使用正则表达式进行模式匹配
这才是 replaceAll 的真正威力所在,假设我们想移除字符串中所有的数字。
String str = "我的电话是138-1234-5678,请拨打!";
// 正则表达式 \d 匹配任何数字 [0-9]
// + 表示一个或多个
String result = str.replaceAll("\\d+", "");
System.out.println(result); // 输出: 我的电话是-,请拨打!
注意: 在 Java 字符串中,反斜杠 \ 是一个转义字符,要表示正则表达式中的 \d,你需要在 Java 字符串中写成 \\d,这是一个非常常见的初学者错误。

关键特性:反向引用 ($1, $2, ...)
这是 replaceAll 最强大也最容易混淆的功能,在 replacement 字符串中,你可以使用 $n 来引用正则表达式中的“捕获组”(capturing group)。
什么是捕获组?
用圆括号 括起来的正则表达式部分就是一个捕获组,在 (\d{3})-(\d{4}) 中:
(\d{3})是第一个捕获组(匹配3个数字)。(\d{4})是第二个捕获组(匹配4个数字)。
反向引用如何工作?
在 replacement 字符串中:
$1会被替换为第一个捕获组匹配到的内容。$2会被替换为第二个捕获组匹配到的内容。- 以此类推。
示例 3:交换日期格式
假设我们有 YYYY-MM-DD 格式的日期,想把它转换成 DD/MM/YYYY 格式。

String dateStr = "2025-10-27";
// 正则表达式解释:
// (\d{4}) -> 捕获组1: 匹配4个数字 (年份)
// - -> 匹配字面量 "-"
// (\d{2}) -> 捕获组2: 匹配2个数字 (月份)
// - -> 匹配字面量 "-"
// (\d{2}) -> 捕获组3: 匹配2个数字 (日期)
String regex = "(\\d{4})-(\\d{2})-(\\d{2})";
// 替换字符串解释:
// $3/$2/$1 -> 用捕获组3(日), 捕获组2(月), 捕获组1(年) 来构建新字符串
String replacement = "$3/$2/$1";
String result = dateStr.replaceAll(regex, replacement);
System.out.println(result); // 输出: 27/10/2025
常见陷阱与注意事项
陷阱 1:混淆 replaceAll 和 replace
| 方法 | 参数类型 | 是否支持正则表达式 | 示例 |
|---|---|---|---|
replaceAll |
(String regex, String replacement) |
是 | s.replaceAll("\\s+", " ") |
replace |
(CharSequence target, CharSequence replacement) |
否 | s.replace(" ", " ") |
错误示例:
// 错误意图:想把所有的 "." 替换成 "-"
String ip = "192.168.1.1";
// . 在正则表达式里是“任意字符”的意思,所以这行代码会报错或产生意外结果
// String wrong = ip.replace(".", "-"); // 这个是OK的,因为replace不支持正则
String right = ip.replaceAll("\\.", "-"); // 必须对 . 进行转义
System.out.println(right); // 输出: 192-168-1-1
陷阱 2:忘记在 Java 字符串中转义反斜杠
这是最最最常见的错误。
| 你想写的正则表达式 | 在 Java 字符串中应该怎么写 | 解释 |
|---|---|---|
\d (匹配数字) |
"\\d" |
第一个 \ 转义了第二个 \,最终编译器看到的是 \d |
\s (匹配空白) |
"\\s" |
同上 |
| (匹配任意字符) | "\\." |
第一个 \ 转义了第二个 ,使其匹配字面量 "." |
\\ (匹配反斜杠) |
"\\\\" |
第一个 \ 转义第二个 \,编译器看到的是 \ |
陷阱 3:反向引用的语法错误
- 错误: 使用
$0。$0指的是整个匹配的字符串,而不是第0个捕获组(捕获组从1开始计数)。 - 错误: 使用
\1,在replacement字符串中,反向引用必须使用 符号,而不是\。\1是在正则表达式本身内部使用的。
陷阱 4:贪婪模式 vs. 懒惰模式
正则表达式默认是“贪婪”的,它会匹配尽可能多的字符。
String html = "<div>第一段</div><div>第二段</div>";
// 贪婪模式: .* 会匹配从第一个 <div> 开始到最后一个 </div> 结束的所有内容
String greedyResult = html.replaceAll("<div>.*</div>", "REPLACED");
System.out.println("贪婪模式结果: " + greedyResult);
// 输出: 贪婪模式结果: REPLACED
// (只替换了一次,因为 .* 匹配了中间的所有内容)
// 懒惰模式: .*? 会匹配尽可能少的字符
String lazyResult = html.replaceAll("<div>.*?</div>", "REPLACED");
System.out.println("懒惰模式结果: " + lazyResult);
// 输出: 懒惰模式结果: REPLACEDREPLACED
// (替换了两次,因为 .*? 在第一个 </div> 处就停止了)
- 是贪婪量词。
- 是懒惰量词。
实用案例
案例 1:清理日志字符串
移除多余的空格和换行符。
String log = " ERROR [main] This is a test message. \n";
// \\s+ 匹配一个或多个空白字符(空格、制表符、换行符等)
String cleanedLog = log.replaceAll("\\s+", " ").trim();
System.out.println(cleanedLog); // 输出: ERROR [main] This is a test message.
案例 2:脱敏处理
隐藏手机号码中间四位。
String phone = "用户手机号是13812345678。";
// 正则表达式解释:
// (\d{3}) -> 捕获前3位
// \d{4} -> 匹配中间4位(不捕获)
// (\d{4}) -> 捕获后4位
String regex = "(\\d{3})\\d{4}(\\d{4})";
// 替换为:捕获组1 + **** + 捕获组2
String replacement = "$1****$2";
String maskedPhone = phone.replaceAll(regex, replacement);
System.out.println(maskedPhone); // 输出: 用户手机号是138****5678。
replaceAll是基于正则表达式的替换工具。regex参数是正则表达式,注意 Java 字符串中的反斜杠需要转义(\\d)。replacement参数可以使用$n语法来引用正则表达式中的捕获组 `(...
