ZetCode

Java Matcher.replaceFirst 方法

上次修改时间:2025 年 4 月 20 日

Matcher.replaceFirst 方法是 Java 正则表达式包的一部分。它将输入序列中第一个与模式匹配的子序列替换为给定的替换字符串。当您只需要修改字符串中模式的第一个出现时,此方法非常有用。

该方法返回一个新字符串,其中第一个匹配项被替换。由于 Java 中的字符串是不可变的,因此原始字符串保持不变。替换可以包含对模式中捕获的组的引用。

replaceFirst 的基本用法

replaceFirst 最简单的用法是用固定字符串替换模式的第一次出现。该方法将替换字符串作为参数,并返回修改后的字符串。原始匹配器的输入保持不变。

ReplaceFirstBasic.java
package com.zetcode;

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

public class ReplaceFirstBasic {

    public static void main(String[] args) {
        
        String input = "The quick brown fox jumps over the lazy dog";
        Pattern pattern = Pattern.compile("fox");
        Matcher matcher = pattern.matcher(input);
        
        String result = matcher.replaceFirst("cat");
        System.out.println("Original: " + input);
        System.out.println("Modified: " + result);
    }
}

在此示例中,我们将 "fox" 的第一次出现替换为 "cat"。replaceFirst 方法扫描输入字符串,并且只替换它找到的第一个匹配项。输出显示原始字符串和修改后的版本。

使用组引用进行替换

replaceFirst 支持对替换字符串中捕获的组的引用。组引用写为 $n,其中 n 是组号。这允许基于匹配内容的动态替换。

ReplaceFirstGroups.java
package com.zetcode;

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

public class ReplaceFirstGroups {

    public static void main(String[] args) {
        
        String input = "John has 3 apples, Jane has 5 oranges";
        Pattern pattern = Pattern.compile("(\\w+) has (\\d+) (\\w+)");
        Matcher matcher = pattern.matcher(input);
        
        String result = matcher.replaceFirst("$1 gave away $2 $3");
        System.out.println("Original: " + input);
        System.out.println("Modified: " + result);
    }
}

此示例捕获三个组:name、quantity 和 item。替换字符串使用这些组来构造一个新句子。只有第一个匹配项被修改,而后续匹配项在输出字符串中保持不变。

不区分大小写的替换

当您需要不区分大小写的匹配以进行替换时,可以使用 CASE_INSENSITIVE 标志。这确保了模式匹配,而无需考虑大小写差异。替换本身不会更改替换字符串的大小写。

ReplaceFirstCaseInsensitive.java
package com.zetcode;

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

public class ReplaceFirstCaseInsensitive {

    public static void main(String[] args) {
        
        String input = "The Quick Brown Fox jumps over the lazy dog";
        Pattern pattern = Pattern.compile("quick", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(input);
        
        String result = matcher.replaceFirst("slow");
        System.out.println("Original: " + input);
        System.out.println("Modified: " + result);
    }
}

在这里,由于 CASE_INSENSITIVE 标志,即使存在大小写差异,"Quick" 也会被匹配。替换字符串 "slow" 以其原始大小写插入。仅替换第一个匹配项,其余的出现次数保持不变。

替换特殊字符

replaceFirst 可以处理包含特殊正则表达式字符的模式。当您的替换字符串包含美元符号或反斜杠时,您需要正确地转义它们。Java 提供了帮助实现此目的的方法。

ReplaceFirstSpecialChars.java
package com.zetcode;

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

public class ReplaceFirstSpecialChars {

    public static void main(String[] args) {
        
        String input = "Price: $10.50, Discount: 5%";
        Pattern pattern = Pattern.compile("\\$\\d+\\.\\d{2}");
        Matcher matcher = pattern.matcher(input);
        
        // Replacement contains $ which is special in regex
        String result = matcher.replaceFirst(Matcher.quoteReplacement("USD 10.50"));
        System.out.println("Original: " + input);
        System.out.println("Modified: " + result);
    }
}

此示例演示了替换包含美元符号的价格模式。Matcher.quoteReplacement 方法转义替换字符串中的特殊字符。这可以防止它们被解释为组引用或其他特殊序列。

使用函数进行替换

Java 9 引入了接受 Function<MatchResult, String>replaceFirst 重载。这允许基于匹配结果的动态替换。该函数接收匹配详细信息并返回替换字符串。

ReplaceFirstFunction.java
package com.zetcode;

import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.function.Function;

public class ReplaceFirstFunction {

    public static void main(String[] args) {
        
        String input = "The temperature is 23.5°C and 75.2°F";
        Pattern pattern = Pattern.compile("(\\d+\\.\\d+)°([CF])");
        Matcher matcher = pattern.matcher(input);
        
        Function converter = match -> {
            double value = Double.parseDouble(match.group(1));
            String unit = match.group(2);
            
            if (unit.equals("F")) {
                double celsius = (value - 32) * 5/9;
                return String.format("%.1f°C", celsius);
            }
            return match.group(); // no conversion for Celsius
        };
        
        String result = matcher.replaceFirst(converter);
        System.out.println("Original: " + input);
        System.out.println("Modified: " + result);
    }
}

此示例将找到的第一个温度(如果是华氏温度)转换为摄氏温度。该函数检查匹配结果并执行转换。仅转换第一个温度,演示了选择性替换。

在多行文本中替换

当处理多行文本时,replaceFirst 可以定位跨多行的第一个匹配项。MULTILINE 标志会更改锚点的工作方式,但不会直接影响替换行为。

ReplaceFirstMultiline.java
package com.zetcode;

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

public class ReplaceFirstMultiline {

    public static void main(String[] args) {
        
        String input = "First line\nSecond line\nThird line";
        Pattern pattern = Pattern.compile("^.*line$", Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(input);
        
        String result = matcher.replaceFirst("Replaced line");
        System.out.println("Original:\n" + input);
        System.out.println("\nModified:\n" + result);
    }
}

此示例替换以 "line" 结尾的第一行。MULTILINE 标志使 ^$ 匹配行边界。替换仅影响多行输入字符串中第一个匹配行。

性能注意事项

当重复使用 replaceFirst 时,重用 Pattern 和 Matcher 对象会更有效。为每次替换创建新的 Pattern 实例由于正则表达式编译而具有显着的开销。

ReplaceFirstPerformance.java
package com.zetcode;

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

public class ReplaceFirstPerformance {

    public static void main(String[] args) {
        
        String[] inputs = {
            "Error: File not found",
            "Error: Permission denied",
            "Warning: Low disk space"
        };
        
        // Efficient approach: reuse compiled pattern
        Pattern pattern = Pattern.compile("Error: ");
        long startTime = System.nanoTime();
        
        for (String input : inputs) {
            Matcher matcher = pattern.matcher(input);
            String result = matcher.replaceFirst("Alert: ");
            System.out.println(result);
        }
        
        long duration = System.nanoTime() - startTime;
        System.out.println("\nTime taken (reusing pattern): " + duration + " ns");
    }
}

此示例演示了重用 Pattern 实例的性能优势。编译后的正则表达式用于多次替换,避免了重新编译。计时显示了与为每次替换编译模式相比,此方法的效率。

来源

Java Matcher.replaceFirst 文档

在本文中,我们探讨了 Matcher.replaceFirst 方法的各个方面。从基本用法到高级技术,此方法为 Java 开发人员提供了强大的字符串操作功能。

作者

我叫 Jan Bodnar,是一位经验丰富的专业程序员。我于 2007 年开始撰写编程文章,至今已撰写超过 1400 篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程