杰瑞科技汇

Java正则replace如何实现替换?

核心方法概览

方法 来源 描述 示例
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()

这是最简单、最常用的方法,适用于大多数替换场景。

Java正则replace如何实现替换?-图1
(图片来源网络,侵删)

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)

只替换第一个匹配的子串。

Java正则replace如何实现替换?-图2
(图片来源网络,侵删)
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 提供了更底层的、基于迭代和缓冲区的替换机制。

工作流程:

  1. 创建一个 Pattern 对象(正则表达式编译后的形式)。
  2. pattern.matcher(str) 创建一个 Matcher 对象。
  3. 创建一个 StringBuffer 来存储结果。
  4. 在一个循环中调用 matcher.find() 来查找下一个匹配项。
  5. 对每个匹配项,调用 matcher.appendReplacement(sb, replacement) 进行替换并追加到 StringBuffer
  6. 循环结束后,调用 matcher.appendTail(sb) 将剩余部分追加到 StringBuffer

示例:反向引用替换

这是 Matcher 最强大的功能之一,你可以在替换字符串 replacement 中引用正则表达式中的捕获组

Java正则replace如何实现替换?-图3
(图片来源网络,侵删)

捕获组是用 括起来的子表达式,在替换字符串中,用 $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) 来获取捕获组的实际内容,然后拼接到替换字符串中。

替换字符串中的特殊字符 ( 和 \)

replaceAllappendReplacementreplacement 参数中, 是一个特殊字符,用于反向引用。

  • $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

总结与最佳实践

  1. 简单替换:优先使用 String.replaceAll()String.replaceFirst(),它们代码简洁,性能良好。
  2. 复杂替换:当替换逻辑需要依赖捕获组内容、或在循环中处理多个匹配项时,使用 MatcherappendReplacement()appendTail() 方法。
  3. 反向引用$n 用于在 replacement 字符串中引用捕获组,这是非常强大的功能。
  4. 转义特殊字符replacement 中需要包含 或 \,记得使用 \\ 进行转义,在 Matcher 方法中,直接拼接 matcher.group(n) 是更安全的方式。
  5. 性能:如果需要对大量字符串进行相同的正则操作,预先编译 Pattern 对象 (Pattern.compile()) 然后重用 Matcher 对象,会比每次都调用 String.replaceAll() 更高效。

希望这份详细的解释能帮助你掌握 Java 中的正则表达式替换!

分享:
扫描分享到社交APP
上一篇
下一篇