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教程。