杰瑞科技汇

Java正则表达式如何替换字符串?

String.replaceAll()replaceFirst()

这是最简单直接的方法,直接在字符串对象上调用。

replaceAll(String regex, String replacement)

  • 功能: 使用给定的正则表达式 regex 替换字符串中所有匹配的子串。
  • 参数:
    • regex: 正则表达式。
    • replacement: 用来替换匹配项的字符串。
  • 返回值: 替换后的新字符串。

replaceFirst(String regex, String replacement)

  • 功能: 使用给定的正则表达式 regex 替换字符串中第一个匹配的子串。
  • 参数:
    • regex: 正则表达式。
    • replacement: 用来替换匹配项的字符串。
  • 返回值: 替换后的新字符串。

重要提示: 这两个方法中的 replacement 字符串是一个字面替换字符串,它支持一些特殊的反斜杠序列来引用捕获组。

  • $0: 表示整个匹配的字符串。
  • $1, $2, ... $9: 表示第一个到第九个捕获组匹配的内容。
  • 表示一个字面的 符号。
  • $&: 表示整个匹配的字符串 (同 $0)。
  • 表示匹配项之前的字符串。
  • 表示匹配项之后的字符串。

示例 1:基本替换

public class RegexReplaceExample {
    public static void main(String[] args) {
        String text = "Hello 123 world 456, welcome to the 789 world.";
        // 将所有数字替换为 "NUMBER"
        String replacedAll = text.replaceAll("\\d+", "NUMBER");
        System.out.println("replaceAll 结果: " + replacedAll);
        // 输出: replaceAll 结果: Hello NUMBER world NUMBER, welcome to the NUMBER world.
        // 只替换第一个数字
        String replacedFirst = text.replaceFirst("\\d+", "FIRST_NUMBER");
        System.out.println("replaceFirst 结果: " + replacedFirst);
        // 输出: replaceFirst 结果: Hello FIRST_NUMBER world 456, welcome to the 789 world.
    }
}

示例 2:使用捕获组进行高级替换

假设我们想将形如 "word1, word2, word3" 的字符串转换为 "word1, word2 and word3"。

public class RegexReplaceWithGroups {
    public static void main(String[] args) {
        String list = "apple, banana, cherry, date";
        // 正则表达式解释:
        // \\s*,\\s* 匹配逗号和它周围可能的空白字符
        // (banana, cherry) 这是一个捕获组,匹配中间的部分
        String result = list.replaceFirst("\\s*,\\s*(banana, cherry)", " and $1");
        System.out.println("替换结果: " + result);
        // 输出: 替换结果: apple and banana, cherry, date
    }
}

一个更通用的例子,将任意数量的单词(用逗号分隔)的最后一个逗号替换为 " and "。

public class RegexReplaceAdvanced {
    public static void main(String[] args) {
        String list = "apple, banana, cherry, date";
        // 正则表达式解释:
        // \\w+ 匹配一个或多个单词字符 (如 apple, banana 等)
        // ,\\s* 匹配一个逗号和它后面的空白
        // (\\w+) 这是一个捕获组,匹配最后一个单词 (如 date)
        // (?=,) 这是一个正向预查,确保后面跟着逗号(但逗号本身不消耗在匹配中)
        // 所以整个正则表达式匹配的是 "cherry, " 这部分,并将 "cherry" 捕获为组1
        String result = list.replaceAll("(\\w+)(?=,)", "$1 and");
        // 这个正则表达式更精确地匹配最后一个逗号前的部分
        // (\\w+)(?=,) 匹配最后一个单词(后面必须跟逗号)
        // ,\\s* 匹配最后的逗号和空白
        // (\\w+) 匹配最后一个单词
        // 我们想保留最后一个单词,只替换前面的部分
        String result2 = list.replaceAll("(\\w+)(?=,)(,\\s*)(\\w+)", "$1 and $3");
        System.out.println("原始字符串: " + list);
        System.out.println("替换结果1: " + result);
        System.out.println("替换结果2: " + result2);
        // 输出:
        // 原始字符串: apple, banana, cherry, date
        // 替换结果1: apple, banana, cherry and date
        // 替换结果2: apple, banana, cherry and date
    }
}

PatternMatcher

当需要更复杂的替换逻辑时(替换的内容需要通过计算得出),使用 PatternMatcher 类会更灵活,这个过程分三步:

  1. 编译正则表达式: Pattern.compile(regex) 创建一个 Pattern 对象。
  2. 创建匹配器: pattern.matcher(input) 创建一个 Matcher 对象。
  3. 执行替换:
    • matcher.replaceAll(replacement): 替换所有匹配项。
    • matcher.replaceFirst(replacement): 替换第一个匹配项。
    • matcher.appendReplacement()matcher.appendTail(): 提供最精细的控制,可以在一个循环中处理匹配项,并在替换前后添加自定义逻辑。

示例 3:使用 Matcher 进行简单替换

这与 String.replaceAll() 功能类似,但为更复杂的操作打下了基础。

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class MatcherReplaceExample {
    public static void main(String[] args) {
        String text = "Order 101 is for 5 apples. Order 102 is for 3 oranges.";
        String regex = "\\d+"; // 匹配数字
        // 1. 编译正则表达式
        Pattern pattern = Pattern.compile(regex);
        // 2. 创建匹配器
        Matcher matcher = pattern.matcher(text);
        // 3. 执行替换
        String result = matcher.replaceAll("[NUM]");
        System.out.println("Matcher replaceAll 结果: " + result);
        // 输出: Matcher replaceAll 结果: Order [NUM] is for [NUM] apples. Order [NUM] is for [NUM] oranges.
    }
}

示例 4:使用 appendReplacement 进行复杂替换

假设我们想把 "Order 101 is for 5 apples" 这样的字符串,替换为 "订单 101: 5 个苹果"。

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class ComplexReplaceExample {
    public static void main(String[] args) {
        String text = "Order 101 is for 5 apples. Order 102 is for 3 oranges.";
        String regex = "Order (\\d+) is for (\\d+) (\\w+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        // 使用 StringBuffer 来构建结果字符串
        StringBuffer sb = new StringBuffer();
        // 循环查找所有匹配项
        while (matcher.find()) {
            // 获取捕获组
            String orderNum = matcher.group(1); // 101, 102
            String quantity = matcher.group(2); // 5, 3
            String item = matcher.group(3); // apples, oranges
            // 定义替换字符串,这里可以加入任何逻辑
            String replacement = "订单 " + orderNum + ": " + quantity + " 个" + item;
            // appendReplacement 会将匹配项之前的内容和替换结果追加到 sb 中
            // 并更新 matcher 的位置到匹配项之后
            matcher.appendReplacement(sb, replacement);
        }
        // appendTail 将最后剩余的部分(最后一个匹配项之后的内容)追加到 sb 中
        matcher.appendTail(sb);
        System.out.println("复杂替换结果: " + sb.toString());
        // 输出: 复杂替换结果: 订单 101: 5 个苹果. 订单 102: 3 个 oranges.
    }
}

总结与对比

方法 来源 灵活性 适用场景
String.replaceAll() java.lang.String 低,替换内容是固定的字符串或简单的 $n 引用。 简单、直接的替换需求。
String.replaceFirst() java.lang.String 低,同上。 只替换第一个匹配项的简单需求。
Matcher.replaceAll() java.util.regex.Matcher 中,替换内容可以是动态计算的字符串。 当替换逻辑比 $n 更复杂时。
Matcher.appendReplacement() java.util.regex.Matcher ,可以在循环中处理每个匹配,并添加自定义逻辑。 最复杂的替换场景,如条件替换、格式化转换等。

常见陷阱与注意事项

  1. 反斜杠 \ 的双重转义: 在 Java 字符串中,\ 是一个转义字符,所以如果你想写一个正则表达式 \d (表示数字),你需要在字符串中写成 "\\d",第一个 \ 用来转义第二个 \,最终才能得到一个 \ 字符给正则表达式引擎。

  2. 贪婪 vs. 懒惰/非贪婪匹配:

    • 贪婪的,它会匹配尽可能多的字符。
    • 懒惰的,它会匹配尽可能少的字符。 这在替换时会产生完全不同的结果。
    String html = "<div>content</div>";
    // 贪婪: 匹配从第一个 < 到最后一个 >
    String greedy = html.replaceAll("<.*>", "REPLACED");
    System.out.println("贪婪匹配: " + greedy); // 输出: REPLACED
    // 懒惰: 匹配从第一个 < 到第一个 >
    String lazy = html.replaceAll("<.*?>", "REPLACED");
    System.out.println("懒惰匹配: " + lazy); // 输出: REPLACEDREPLACED
  3. replaceAll 中的 符号: 如果你的替换字符串中包含一个字面的 符号,必须写成 ,否则 会被解释为对捕获组的引用。

    String text = "ID: 123";
    // 错误: 会抛出 IllegalArgumentException: group 1 not found
    // String wrong = text.replaceFirst("ID: (\\d+)", "Price: $$1");
    // 正确
    String correct = text.replaceFirst("ID: (\\d+)", "Price: $$1");
    System.out.println(correct); // 输出: Price: $1

希望这份详细的指南能帮助你掌握 Java 中正则表达式替换的用法!

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