杰瑞科技汇

Java replace方法支持正则表达式吗?

核心方法概览

  1. String.replaceAll(String regex, String replacement)

    • 功能: 将字符串中所有匹配正则表达式的子字符串替换为指定的 replacement 字符串。
    • 返回值: 一个新的字符串,替换完成后的结果。
    • 特点: 简单易用,适用于全局替换。
  2. String.replaceFirst(String regex, String replacement)

    • 功能: 将字符串中第一个匹配正则表达式的子字符串替换为指定的 replacement 字符串。
    • 返回值: 一个新的字符串,替换完成后的结果。
    • 特点: 适用于只替换第一个匹配项的场景。
  3. Matcher.appendReplacement(StringBuffer sb, String replacement)

    • 功能: 这是 java.util.regex.Matcher 类中的核心方法,用于执行复杂的替换操作。
    • 工作方式: 它会从当前匹配位置开始,将上一个匹配结束位置到当前匹配开始位置之间的文本(即未匹配的部分)追加到 StringBuffer 中,然后将 replacement 字符串追加进去,并更新 Matcher 的状态,使其指向下一个匹配位置。
    • 特点: 非常灵活,可以在替换过程中引用分组,并且可以结合循环进行多次替换。
  4. Matcher.appendTail(StringBuffer sb)

    • 功能: 在 appendReplacement() 循环结束后,将最后一个匹配项之后的所有剩余文本追加到 StringBuffer 中。
    • 特点: 必须在 appendReplacement() 循环之后调用,以完成整个字符串的构建。

replaceAll()replaceFirst() - 简单直接

这是最常用的方法,语法简单,适合大多数场景。

replaceAll() 示例

public class RegexReplaceExample {
    public static void main(String[] args) {
        String text = "Hello 123 World 456, and 789.";
        // 目标:将所有的数字替换为 "[NUMBER]"
        String regex = "\\d+"; // \d+ 匹配一个或多个数字
        String replacement = "[NUMBER]";
        String result = text.replaceAll(regex, replacement);
        System.out.println("原始文本: " + text);
        System.out.println("替换后文本: " + result);
        // 输出: 替换后文本: Hello [NUMBER] World [NUMBER], and [NUMBER].
    }
}

replaceFirst() 示例

public class RegexReplaceFirstExample {
    public static void main(String[] args) {
        String text = "apple banana apple cherry";
        // 目标:只替换第一个 "apple"
        String regex = "apple";
        String replacement = "orange";
        String result = text.replaceFirst(regex, replacement);
        System.out.println("原始文本: " + text);
        System.out.println("替换后文本: " + result);
        // 输出: 替换后文本: orange banana apple cherry
    }
}

Matcher 类的替换方法 - 高度灵活

当你需要更复杂的逻辑时,比如在替换字符串中引用匹配到的分组,或者想对匹配到的内容进行二次处理,就必须使用 Matcher 类。

核心步骤:

  1. 编译正则表达式,得到 Pattern 对象。
  2. Pattern 对象和原始文本创建 Matcher 对象。
  3. 创建一个 StringBuffer 用于存储结果。
  4. 使用 while (matcher.find()) 循环查找所有匹配项。
  5. 在循环内调用 matcher.appendReplacement(sb, replacement)
  6. 循环结束后,调用 matcher.appendTail(sb)
  7. StringBuffer 中获取最终结果。

示例:在替换中引用分组

这是一个非常经典和有用的功能,在 replacement 字符串中,可以使用 $n 来引用第 n 个分组(从1开始)。

场景:将格式为 "姓氏,名字" 的文本转换为 "名字 姓氏"。

import java.util.regex.*;
public class MatcherReplaceWithGroupExample {
    public static void main(String[] args) {
        String text = "Doe,John; Smith,Jane; Watson,Sherlock";
        // 正则表达式: 捕获姓氏和名字
        // (\\w+) 匹配并捕获姓氏
        // ,\\s* 匹配逗号和可能的空格
        // (\\w+) 匹配并捕获名字
        String regex = "(\\w+),\\s*(\\w+)";
        // 替换字符串: $2 对应第二个分组 (名字), $1 对应第一个分组 (姓氏)
        String replacement = "$2 $1";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        StringBuffer sb = new StringBuffer();
        // 循环查找并替换所有匹配项
        while (matcher.find()) {
            // 将 "Doe,John" 替换为 "John Doe"
            matcher.appendReplacement(sb, replacement);
        }
        // 将剩余部分(如最后的分号)追加到结果中
        matcher.appendTail(sb);
        String result = sb.toString();
        System.out.println("原始文本: " + text);
        System.out.println("替换后文本: " + result);
        // 输出: 替换后文本: John Doe; Jane Smith; Sherlock Watson
    }
}

示例:动态生成替换内容

如果你想根据匹配到的内容动态决定替换什么,可以在 appendReplacement 循环内部进行判断。

场景:将文本中的所有数字替换为其对应的英文单词,但只替换两位数(10-99)。

import java.util.regex.*;
public class DynamicReplacementExample {
    public static void main(String[] args) {
        String text = "I have 5 apples, 12 oranges, and 99 bananas.";
        String regex = "\\d+"; // 匹配所有数字
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String matchedNumber = matcher.group(); // 获取匹配到的字符串,如 "12"
            int num = Integer.parseInt(matchedNumber);
            String replacement;
            if (num >= 10 && num <= 99) {
                // 动态生成替换内容
                replacement = getNumberInWords(num);
            } else {
                // 不满足条件,替换为原样
                replacement = matchedNumber;
            }
            matcher.appendReplacement(sb, replacement);
        }
        matcher.appendTail(sb);
        System.out.println("原始文本: " + text);
        System.out.println("替换后文本: " + sb.toString());
        // 输出: 替换后文本: I have 5 apples, twelve oranges, and ninety-nine bananas.
    }
    // 一个简单的辅助方法,将两位数转为英文单词(简化版)
    private static String getNumberInWords(int num) {
        String[] tens = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
        String[] ones = {"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
        if (num < 10 || num > 99) return String.valueOf(num);
        int tenDigit = num / 10;
        int oneDigit = num % 10;
        if (oneDigit == 0) {
            return tens[tenDigit];
        } else {
            return tens[tenDigit] + "-" + ones[oneDigit];
        }
    }
}

重要注意事项

反斜杠 \ 的双重转义

在 Java 字符串中,反斜杠 \ 是一个转义字符,所以当你想在正则表达式中使用 \d (表示数字) 时,必须在 Java 字符串中写成 "\\d"

  • 正则表达式: \d+
  • Java 字符串: "\\d+"

replacement 字符串中的特殊含义

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

  • $1, $2, ...: 引用第1, 2, ...个分组。
  • $0: 引用整个匹配的子串。

如果你想在替换字符串中插入一个字面的 符号,你需要对它进行转义,写成 \$

示例

String text = "price: 100";
// 错误用法: 会抛出 IllegalArgumentException,因为 "$100" 试图引用一个不存在的第100个分组
// String result = text.replaceAll("\\d", "$100"); 
// 正确用法: 插入一个字面的 '$'
String result = text.replaceAll("\\d", "\\$$0"); // $0 代表整个匹配的数字
System.out.println(result); // 输出: price: $100
方法 用途 简单性 灵活性
replaceAll() 全局替换 中 (支持 $n 分组引用)
replaceFirst() 替换第一个匹配项 中 (支持 $n 分组引用)
Matcher.appendReplacement() 复杂、动态替换 (可循环、可编程、支持 $n)
  • 日常使用:优先选择 replaceAll()replaceFirst(),它们简洁明了。
  • 高级需求:当需要引用分组、动态生成替换内容或对匹配项进行复杂处理时,使用 Matcher 类的 appendReplacement()appendTail() 方法。
分享:
扫描分享到社交APP
上一篇
下一篇