正則表達式是字符串處理的「瑞士軍刀」,Java 通過 java.util.regex 包及 String 便利方法提供強大支持。本文聚焦匹配、切割、替換三大核心操作,結合實戰案例講解 API 用法、常見陷阱及性能優化技巧。
| 操作類型 | String 便利方法 | Regex 核心類 | 適用場景 |
|---|---|---|---|
| 匹配驗證 | str.matches(regex) | Pattern.matches(regex, str) | 整字符串完全匹配校驗 |
| 查找提取 | 無 | Matcher.find()/group() | 子串查找、分組捕獲、多次匹配 |
| 切割分隔 | str.split(regex) | Pattern.split(str) | 分隔符分割、保留分隔符 |
| 替換重寫 | str.replaceAll/replaceFirst | Matcher.replaceAll/replaceFirst | 全局/首次替換、引用分組 |
import java.util.Scanner;
public class RegexMatchDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("請輸入手機號: ");
String input = sc.nextLine();
validatePhone(input);
}
private static void validatePhone(String str) {
// 手機號:1開頭,第二位3-9,共11位
String regex = "^1[3-9]\\d{9}$";
// String.matches() 要求整串匹配,無需 ^$
if (str.matches(regex)) {
System.out.println("✅ 匹配成功: 有效手機號");
} else {
System.out.println("❌ 匹配失敗: 格式錯誤");
}
}
}
// 預定義字符類
\d = [0-9] // 數字
\D = [^0-9] // 非數字
\w = [a-zA-Z0-9_] // 單詞字符
\W = [^a-zA-Z0-9_] // 非單詞字符
\s = [ \t\n\r\f] // 空白字符
\S = [^ \t\n\r\f] // 非空白字符
// 量詞
? 0或1次
* 0或多次
+ 1或多次
{n} 精確n次
{n,} 至少n次
{n,m} n到m次
public class RegexSplitDemo {
public static void main(String[] args) {
String input = "Java Python\tGo\nRust C++";
// 匹配「一個或多個空白字符」作為分隔符
String regex = "\\s+";
String[] langs = input.split(regex);
System.out.println("切割結果:");
for (String lang : langs) {
System.out.println(" - " + lang);
}
// 進階:保留分隔符 (正向前瞻/後顧)
String[] withDelim = input.split("(?<=\\s)|(?=\\s)");
// 結果: ["Java", " ", "Python", "\t", "Go", "\n", "Rust", " ", "C++"]
}
}
split("|") 按字符切割,需轉義 split("\\|") 或 split("[|]")。"a,b,".split(",") → ["a", "b"];保留用 split(",", -1) → ["a", "b", ""]。Pattern.compile(regex) 復用。
public class RegexReplaceDemo {
public static void main(String[] args) {
String text = "價格: 99元, 原價: 199元, VIP價: 88元";
// 1. 簡單替換:所有數字替換為 *
String masked = text.replaceAll("\\d+", "*");
System.out.println("掩碼: " + masked);
// 價格: *元, 原價: *元, VIP價: *元
// 2. 分組引用替換:格式化手機號 138****1234
String phone = "13812345678";
String maskedPhone = phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
System.out.println("手機掩碼: " + maskedPhone);
// 3. 回調式替換 (Java 9+ Matcher.replaceAll(Function))
String calculated = text.replaceAll("\\d+", m ->
String.valueOf(Integer.parseInt(m.group()) * 2)
);
System.out.println("價格雙倍: " + calculated);
}
}
| 技巧 | 語法 | 示例 | 說明 |
|---|---|---|---|
| 分組引用 | $1, $2 / \1, \2 | replaceAll("(\\w+) (\\w+)", "$2 $1") | 交換單詞順序 |
| 轉義替換字符串 | Matcher.quoteReplacement(str) | replaceAll(regex, Matcher.quoteReplacement("$100")) | 避免 $ 被識別為分組引用 |
| 大小寫轉換 | \U, \L, \u, \l | replaceAll("(\\w)", "\U$1") | 首字母大寫 (需 Pattern.CASE_INSENSITIVE) |
| 條件替換 | Matcher.replaceAll(Function) | m -> m.group().toUpperCase() | Java 9+,動態計算替換值 |
Pattern p = Pattern.compile(regex); Matcher m = p.matcher(input); 避免重複編譯。str.replace(old, new)(不走正則,更快)。(a+)+、模糊匹配 .*,優先用確定性字符類 [^"]*。m.reset(newInput) 重置輸入,避免重建對象。Pattern.CASE_INSENSITIVE | Pattern.DOTALL 替換字符串標志 "(?is)"。Java 正則操作核心在於 Pattern 編譯 → Matcher 狀態機 → 三大動作 (匹配/切割/替換)。掌握 matches 整串匹配、split 多字符分割、replaceAll 分組引用與回調替換,配合預編譯復用與避免回溯陷阱,即可高效解決 95% 字符串處理需求。