核心概念
replaceAll 是 Java String 类的一个方法,它的作用是使用给定的正则表达式替换字符串中所有匹配的子字符串。

方法签名
public String replaceAll(String regex, String replacement)
regex: 你要查找的正则表达式,这是replaceAll与replace最关键的区别。replacement: 用于替换匹配内容的字符串。
replaceAll vs. replace
这是初学者最容易混淆的地方,让我们用一个表格来对比它们:
| 特性 | replaceAll(String regex, String replacement) |
replace(CharSequence target, CharSequence replacement) |
|---|---|---|
| 第一个参数 | 正则表达式 | 普通字符串 |
| 功能 | 查找所有匹配正则表达式的子串,并替换 | 查找所有完全匹配的普通子串,并替换 |
| 特殊字符 | ^ \ [] 等在正则中有特殊含义 |
等字符被视为普通字符,没有特殊含义 |
| 适用场景 | 需要按规则(如“所有数字”、“所有空格”)进行替换时 | 需要替换一个固定、已知的字符串时 |
简单总结:
- 想替换固定的字符串(比如把 "apple" 换成 "orange"),用
replace。 - 想替换符合某种模式的字符串(比如把所有数字去掉,把所有空格换成逗号),用
replaceAll。
replaceAll 的详细使用与示例
示例 1:最简单的替换(等同于 replace)
如果你只想替换一个固定的字符串,但又用了 replaceAll,需要把第一个参数进行转义,否则里面的特殊字符会被当作正则表达式处理。
String str = "hello.world.java";
// 错误示范:. 在正则中表示"任意字符",所以会替换掉所有字符
// String result1 = str.replaceAll(".", "_"); // 输出: "_____________"
// 正确做法:使用 \\ 对 . 进行转义,让它代表一个普通的点号
String result = str.replaceAll("\\.", "_");
System.out.println(result); // 输出: hello_world_java
为什么是 \\. 而不是 \.?
因为在 Java 的字符串字面量中,\ 是一个转义字符,要表示一个反斜杠本身,你需要写成 \\。\\. 在编译后,实际上传递给 replaceAll 方法的就是 \.,这正是正则表达式用来匹配一个字面点号的方式。

示例 2:常见的正则表达式替换
这才是 replaceAll 大显身手的地方。
场景 1:移除所有数字
String text = "我的电话是13812345678,邮箱是test@example.com。";
String result = text.replaceAll("\\d", ""); // \d 表示任意一个数字
System.out.println(result); // 输出: 我的电话是,邮箱是test@example.com。
场景 2:移除所有非数字字符
String text = "订单号:A123-B456-C789";
String result = text.replaceAll("[^0-9]", ""); // [^...] 表示"非"
System.out.println(result); // 输出: 123456789
场景 3:规范化空格(多个空格变一个)

String text = "这个 句子 有很多 不必要的 空格。";
// \\s+ 表示匹配一个或多个空白字符(空格、制表符、换行等)
String result = text.replaceAll("\\s+", " ");
System.out.println(result); // 输出: 这个 句子 有很多 不必要的 空格。
场景 4:移除行首行尾的空白
String text = " \n hello java \n \t ";
// ^ 表示行首,$ 表示行尾,\\s 表示空白字符
String result = text.replaceAll("^\\s+|\\s+$", "");
System.out.println("---" + result + "---"); // 输出: ---hello java---
replaceAll 中 replacement 参数的技巧
replacement 参数不仅可以是普通字符串,还可以包含一些特殊的反向引用。
反向引用
反向引用允许你引用正则表达式中的分组,分组是用 创建的。
$1:引用第一个分组$2:引用第二个分组$0:引用整个匹配的字符串
示例:交换两个单词
假设我们要把 "firstName lastName" 变成 "lastName firstName"。
String name = "John Doe";
// (\\w+) 是第一个分组,匹配 "John"
// (\\s+) 是第二个分组,匹配空格
// (\\w+) 是第三个分组,匹配 "Doe"
String result = name.replaceAll("(\\w+)(\\s+)(\\w+)", "$3$2$1");
System.out.println(result); // 输出: Doe John
替换为美元符号
如果你想直接在替换字符串中使用 字符本身,而不是把它当作反向引用的开头,你需要对它进行转义。
String price = "价格是$99.99。";
// 错误示范:$9 会被当作反向引用,但正则中没有第9个分组,会抛出异常
// String result1 = price.replaceAll("\\d+", "价格是$$$。"); // 报错
// 正确做法:用 \$ 来转义
String result = price.replaceAll("\\d+", "价格是$$。");
System.out.println(result); // 输出: 价格是$。
常见错误与注意事项
-
忘记转义正则特殊字符 这是最常见的错误,当你想匹配 等字符时,一定要记得用
\转义,在 Java 字符串中就是\\。// 错误 "100.5".replace(".", ","); // 这是可以的,因为 replace 不认识正则 "100.5".replaceAll(".", ","); // 错误,会把每个字符都替换掉 // 正确 "100.5".replaceAll("\\.", ","); // 输出 "100,5" -
正则表达式语法错误 如果你的正则表达式本身写错了(比如括号不匹配),
replaceAll会抛出PatternSyntaxException异常。 -
性能考虑 对于简单的、非正则的字符串替换,
replace方法通常比replaceAll性能更好,因为它不需要经过正则表达式引擎的复杂解析。
总结与最佳实践
| 任务 | 推荐方法 | 示例 |
|---|---|---|
| 替换固定字符串 | replace() |
"hello".replace("ll", "rr"); -> "herro" |
| 按模式替换(正则) | replaceAll() |
"a1b2c3".replaceAll("\\d", "x"); -> "axbxcx" |
| 替换第一个匹配项 | replaceFirst() |
"hello world".replaceFirst("l", "z"); -> "hezlo world" |
记住这个核心原则:replaceAll 的第一个参数是“规则”(正则表达式),而不是“字符串”,理解了这一点,你就能灵活、正确地使用它来处理各种复杂的字符串替换需求。
