Java Matcher.appendReplacement 方法
上次修改时间:2025 年 4 月 20 日
appendReplacement 方法是 Java 中 java.util.regex 包中 Matcher 类的一部分。 它对输入字符串执行增量替换操作,同时保留非匹配部分。
此方法通常与 appendTail 结合使用,以构建修改后的字符串,其中仅替换特定的匹配项。 通过允许对每个匹配项进行自定义处理,它提供了比简单替换方法更多的控制。
基本定义
Matcher.appendReplacement(StringBuffer sb, String replacement) 将文本附加到字符串缓冲区并执行替换。 它读取输入文本直到当前匹配项,并将其附加到缓冲区,然后附加替换字符串。
该方法需要一个 StringBuffer 来累积结果,以及一个可以引用捕获组的替换字符串。 如果没有尝试匹配或先前的匹配失败,它会抛出 IllegalStateException 异常。
基本替换示例
此示例演示了 appendReplacement 的基本用法,用于替换字符串中模式的所有出现项。 我们将用它们的文字等价物替换所有数字。
package com.zetcode;
import java.util.regex.*;
public class BasicReplacement {
public static void main(String[] args) {
String input = "I have 3 apples and 5 oranges.";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String replacement = convertToWord(matcher.group());
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);
System.out.println("Original: " + input);
System.out.println("Modified: " + sb.toString());
}
private static String convertToWord(String number) {
switch (number) {
case "1": return "one";
case "2": return "two";
case "3": return "three";
case "4": return "four";
case "5": return "five";
default: return number;
}
}
}
在此示例中,我们首先编译一个模式来匹配数字。 匹配器找到每个数字序列,并且对于每个匹配,我们调用 appendReplacement 并进行自定义替换。 最后,appendTail 添加最后一个匹配项之后剩余的文本。
在替换中使用组引用
此示例显示了如何在替换字符串中引用捕获组。 我们将日期格式从 “MM/DD/YYYY” 重新格式化为 “YYYY-MM-DD” 格式。
package com.zetcode;
import java.util.regex.*;
public class GroupReference {
public static void main(String[] args) {
String input = "Dates: 12/25/2023, 01/01/2024, 07/04/2023";
Pattern pattern = Pattern.compile("(\\d{2})/(\\d{2})/(\\d{4})");
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "$3-$1-$2");
}
matcher.appendTail(sb);
System.out.println("Original: " + input);
System.out.println("Modified: " + sb.toString());
}
}
在这里,我们在替换字符串中使用组引用 ($1, $2, $3) 来重新排列日期组成部分。 该模式将月、日和年捕获为单独的组,然后我们在替换字符串中引用它们。
条件替换
此示例演示了基于匹配内容的条件替换。 我们将用它们的长度替换单词,但前提是它们超过 3 个字符。
package com.zetcode;
import java.util.regex.*;
public class ConditionalReplacement {
public static void main(String[] args) {
String input = "The quick brown fox jumps over the lazy dog";
Pattern pattern = Pattern.compile("\\w+");
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String word = matcher.group();
String replacement = word.length() > 3 ?
String.valueOf(word.length()) : word;
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);
System.out.println("Original: " + input);
System.out.println("Modified: " + sb.toString());
}
}
该代码检查每个匹配单词的长度,并且仅当它超过 3 个字符时才用其字符计数替换它。 这表明 appendReplacement 如何实现简单的替换方法无法处理的复杂替换逻辑。
HTML 标签转换
此示例将简单的 markdown 样式格式转换为 HTML 标签。 我们将 *bold* 文本替换为 <b>bold</b>,并将 _italic_ 替换为 <i>italic</i>。
package com.zetcode;
import java.util.regex.*;
public class HtmlConversion {
public static void main(String[] args) {
String input = "This is *bold* and this is _italic_ text.";
Pattern boldPattern = Pattern.compile("\\*(.*?)\\*");
Pattern italicPattern = Pattern.compile("_(.*?)_");
StringBuffer sb = new StringBuffer();
Matcher matcher = boldPattern.matcher(input);
// First replace bold
while (matcher.find()) {
matcher.appendReplacement(sb, "<b>$1</b>");
}
matcher.appendTail(sb);
// Then replace italic in the modified string
String intermediate = sb.toString();
matcher = italicPattern.matcher(intermediate);
sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "<i>$1</i>");
}
matcher.appendTail(sb);
System.out.println("Original: " + input);
System.out.println("Modified: " + sb.toString());
}
}
此示例显示了两个替换过程 - 首先是粗体,然后是斜体格式。 我们在第二个过程中处理第一个替换的中间结果。 请注意使用非贪婪量词 (.*?) 来匹配标记之间最短的可能文本。
自定义替换逻辑
此示例演示了复杂的替换逻辑,我们在替换之前处理每个匹配项。 我们将通过用星号替换字符来混淆电子邮件地址,但第一个和最后一个字符除外。
package com.zetcode;
import java.util.regex.*;
public class CustomLogic {
public static void main(String[] args) {
String input = "Contact us at support@example.com or sales@company.org";
Pattern pattern = Pattern.compile("\\b[\\w.%-]+@[\\w.-]+\\.[a-zA-Z]{2,6}\\b");
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String email = matcher.group();
String obfuscated = obfuscateEmail(email);
matcher.appendReplacement(sb, obfuscated);
}
matcher.appendTail(sb);
System.out.println("Original: " + input);
System.out.println("Modified: " + sb.toString());
}
private static String obfuscateEmail(String email) {
String[] parts = email.split("@");
String local = parts[0];
String domain = parts[1];
// Obfuscate local part (keep first and last character)
if (local.length() > 2) {
local = local.charAt(0) + "*".repeat(local.length() - 2) +
local.charAt(local.length() - 1);
}
return local + "@" + domain;
}
}
该示例显示了如何将 appendReplacement 与每个匹配项的自定义处理逻辑一起使用。 我们分割电子邮件地址,处理本地部分,然后将其重新组合以进行替换。
多行替换
此示例演示了如何使用 appendReplacement 处理多行输入。 我们将行号添加到多行字符串中的每一行。
package com.zetcode;
import java.util.regex.*;
public class MultilineProcessing {
public static void main(String[] args) {
String input = "First line\nSecond line\nThird line\nFourth line";
Pattern pattern = Pattern.compile("^.*$", Pattern.MULTILINE);
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
int lineNumber = 1;
while (matcher.find()) {
String replacement = lineNumber + ": " + matcher.group();
matcher.appendReplacement(sb, replacement);
lineNumber++;
}
matcher.appendTail(sb);
System.out.println("Original:\n" + input);
System.out.println("\nModified:\n" + sb.toString());
}
}
这里的关键是使用 Pattern.MULTILINE 标志来使 ^ 和 $ 在每行的开头和结尾处匹配。 我们维护一个计数器,以便在使用 appendReplacement 处理每一行时对其进行编号。
带有反向引用的复杂模式
这个高级示例显示了如何在模式和替换中使用反向引用。 我们将找到重复的单词并在输出中标记它们。
package com.zetcode;
import java.util.regex.*;
public class DuplicateWords {
public static void main(String[] args) {
String input = "This this is a test test of duplicate word detection.";
Pattern pattern = Pattern.compile("\\b(\\w+)(\\s+\\1\\b)+", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "[DUPLICATE: $1]");
}
matcher.appendTail(sb);
System.out.println("Original: " + input);
System.out.println("Modified: " + sb.toString());
}
}
模式 \b(\w+)(\s+\1\b)+ 匹配重复的单词。 替换使用 $1 来引用第一个捕获组(重复的单词)。 CASE_INSENSITIVE 标志确保大小写差异不会阻止重复项的检测。
来源
Java Matcher.appendReplacement 文档
本教程涵盖了 Matcher.appendReplacement 的各种用途,从基本到高级场景。 当与正则表达式结合使用时,该方法提供了强大的字符串操作功能。
作者
列出所有Java教程。