一文秒懂Java 中 Matcher.appendReplacement() 和 Matcher.appendTail() 这两个重要的正则处理方法

详细解释 Java 中 Matcher.appendReplacement()Matcher.appendTail() 这两个重要的字符串处理方法。

1. Matcher.appendReplacement()

功能描述

appendReplacement() 方法用于在匹配到模式时,将匹配结果之前的文本和替换后的文本追加到 StringBuffer 中。

方法签名

public Matcher appendReplacement(StringBuffer sb, String replacement)

工作原理

  1. 从上次匹配结束位置到当前匹配开始位置之间的文本被追加到 StringBuffer
  2. 将替换字符串(可以包含反向引用)追加到 StringBuffer
  3. 更新匹配位置

替换字符串中的特殊字符

  • $n - 引用第 n 个捕获组(n 为 1-9)
  • $0 - 引用整个匹配
  • $<name> - 引用命名捕获组(Java 7+)
  • \\ - 转义字符

2. Matcher.appendTail()

功能描述

appendTail() 方法用于在完成所有替换后,将剩余未处理的文本追加到 StringBuffer 中。

方法签名

public StringBuffer appendTail(StringBuffer sb)

3. 完整示例

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class AppendReplacementExample {
    public static void main(String[] args) {
        String input = "The quick brown fox jumps over the lazy dog";
        String regex = "\\b\\w{4}\\b"; // 匹配4个字母的单词
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        StringBuffer result = new StringBuffer();
        
        // 使用 appendReplacement 进行替换
        while (matcher.find()) {
            //获取匹配到的字符串
            String matchedWord = matcher.group();
            //替换为大写
            String replacement = "[" + matchedWord.toUpperCase() + "]";
            
            System.out.println("找到匹配: '" + matchedWord + "',位置: " + 
                             matcher.start() + "-" + matcher.end());
            
            matcher.appendReplacement(result, replacement);
            System.out.println("当前结果: " + result.toString());
        }
        
        // 使用 appendTail 完成处理
        matcher.appendTail(result);
        
        System.out.println("\n最终结果: " + result.toString());
    }
}

输出:

找到匹配: 'quick',位置: 4-9
当前结果: The [QUICK]
找到匹配: 'jumps',位置: 20-25
当前结果: The [QUICK] brown fox [JUMPS]
找到匹配: 'over',位置: 26-30
当前结果: The [QUICK] brown fox [JUMPS] [OVER]
找到匹配: 'lazy',位置: 35-39
当前结果: The [QUICK] brown fox [JUMPS] [OVER] the [LAZY]

最终结果: The [QUICK] brown fox [JUMPS] [OVER] the [LAZY] dog

4. 使用反向引用的示例

public class BackReferenceExample {
    public static void main(String[] args) {
        String input = "John Smith, Jane Doe, Bob Johnson";
        String regex = "(\\w+) (\\w+)"; // 捕获名和姓
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        StringBuffer result = new StringBuffer();
        
        // 交换名和姓的位置,并添加格式
        while (matcher.find()) {
            // $2 引用第二个捕获组(姓),$1 引用第一个捕获组(名)
            matcher.appendReplacement(result, "$2, $1");
        }
        
        matcher.appendTail(result);
        
        System.out.println("原始: " + input);
        System.out.println("处理后: " + result.toString());
    }
}

输出:

原始: John Smith, Jane Doe, Bob Johnson
处理后: Smith, John, Doe, Jane, Johnson, Bob

5. 更复杂的替换示例

public class ComplexReplacement {
    public static void main(String[] args) {
        String html = "<p>价格: $10.50</p><div>总计: $25.00</div>";
        String regex = "\\$([0-9]+\\.[0-9]{2})";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(html);
        
        StringBuffer result = new StringBuffer();
        
        while (matcher.find()) {
            double amount = Double.parseDouble(matcher.group(1));
            double converted = amount * 0.85; // 假设汇率转换
            String replacement = String.format("€%.2f", converted);
            
            matcher.appendReplacement(result, replacement);
        }
        
        matcher.appendTail(result);
        
        System.out.println("原始HTML: " + html);
        System.out.println("转换后: " + result.toString());
    }
}

输出:

原始HTML: <p>价格: $10.50</p><div>总计: $25.00</div>
转换后: <p>价格: €8.93</p><div>总计: €21.25</div>

6. 实用工具方法示例

public class RegexUtils {
    
    /**
     * 自定义替换方法,使用函数式接口处理每个匹配
     */
    public static String replaceAll(String input, String regex, 
                                   java.util.function.Function<String, String> replacer) {
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        StringBuffer result = new StringBuffer();
        
        while (matcher.find()) {
            String replacement = replacer.apply(matcher.group());
            matcher.appendReplacement(result, replacement);
        }
        
        matcher.appendTail(result);
        return result.toString();
    }
    
    public static void main(String[] args) {
        String text = "我的电话是123-4567,另一个是890-1234";
        
        // 使用lambda表达式进行替换
        String masked = replaceAll(text, "\\d{3}-\\d{4}", 
            match -> "***-****");
        
        System.out.println("原始: " + text);
        System.out.println("脱敏后: " + masked);
    }
}

关键要点

  1. 必须配合使用: appendReplacement()appendTail() 通常一起使用
  2. 状态维护: appendReplacement() 会维护匹配位置状态
  3. 性能优势: 对于大文本,比 String.replaceAll() 更高效
  4. 灵活性: 支持复杂的替换逻辑和反向引用
  5. 线程安全: 单个 Matcher 实例不是线程安全的

这两个方法为复杂的字符串替换操作提供了强大而灵活的工具。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值