正則表達式是處理文本模式匹配、提取、轉換的利器。Java 通過 java.util.regex 包(Pattern、Matcher)及 String 便利方法(matches、split、replaceAll/First)提供完整支持。本文聚焦三大核心操作場景,結合實戰案例、常見陷阱、效能優化與最佳實踐。
| 類/方法 | 用途 | 特點 |
|---|---|---|
Pattern.compile(regex) | 編譯正則為 Pattern 對象 | 線程安全、可復用、支援標誌位 |
Pattern.matches(regex, input) | 一次性匹配整個字符串 | 等價 Pattern.compile(regex).matcher(input).matches(),不復用 |
matcher(input) | 創建 Matcher 進行操作 | 非線程安全、狀態化、支援 find/group/replace |
String.matches(regex) | 全字符串匹配 | 常用於驗證 |
String.split(regex, limit) | 切割字符串 | 返回 String[],limit 控制結果長度 |
String.replaceAll(regex, repl) | 全量替換 | 支援 $1 $2 回引用 |
String.replaceFirst(regex, repl) | 首次替換 | 同上 |
Matcher.replaceAll/replaceFirst | 替換並獲取結果 | 可在替換邏輯中動態計算 |
Matcher.appendReplacement/tail | 流式構建替換結果 | 高效處理大文本 |
String.matches()
// 驗證 QQ 號:首位 1-9,長度 5-11 位數字
String regex = "[1-9]\\d{4,10}";
String qq = "123456";
boolean valid = qq.matches(regex); // true
// 常見驗證正則
String emailRegex = "^[\\w.-]+@[\\w-]+(\\.[\\w-]+)+$";
String phoneRegex = "^1[3-9]\\d{9}$"; // 中國大陸手機
String idCardRegex = "^\\d{17}[\\dXx]$"; // 18 位身份證(簡化)
注意: matches() 默認匹配整個字符串,等同於 ^regex$,無需顯式加錨點。
Matcher.find() + group()
String text = "訂單號: NO20240115001, 金額: ¥123.45, 用戶: user_abc";
Pattern p = Pattern.compile("NO\\d{12}|¥\\d+\\.\\d{2}|user_\\w+");
Matcher m = p.matcher(text);
while (m.find()) {
System.out.println("匹配: " + m.group()); // 依次輸出三個匹配
}
// 分組提取
Pattern p2 = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m2 = p2.matcher("今天是 2024-01-15");
if (m2.find()) {
System.out.println("年: " + m2.group(1)); // 2024
System.out.println("月: " + m2.group(2)); // 01
System.out.println("日: " + m2.group(3)); // 15
System.out.println("全匹配: " + m2.group(0)); // 2024-01-15
}
| 語法 | 含義 | 示例 |
|---|---|---|
\\d | 數字 [0-9] | \\d{3} 三位數 |
\\D | 非數字 | |
\\w | 單詞字符 [a-zA-Z0-9_] | |
\\W | 非單詞字符 | |
\\s | 空白字符 (空格、制表、換行) | \\s+ 多個空白 |
\\S | 非空白 | |
. | 任意字符(除換行,單行模式除外) | |
^ $ | 行首/行尾(多行模式)或字符串首/尾 | |
\\b \\B | 單詞邊界/非邊界 | \\bcat\\b 匹配單詞 cat |
(?=...) (?!...) | 正向/負向前瞻(零寬斷言) | \\d+(?=元) 匹配「100」在「100元」中 |
(?<=...) (?<!...) | 正向/負向後顧(固定寬度) | (?<=¥)\\d+ 匹配「¥100」中的「100」 |
| 場景 | 推薦 | 理由 |
|---|---|---|
| 驗證整個字符串格式 | String.matches() / Pattern.matches() | 語義清晰、自動錨定首尾 |
| 提取多個匹配/分組 | Matcher.find() + group() | 唯一可獲取分組信息 |
| 簡單切割 | String.split() | 便捷、返回數組 |
| 複雜切割/保留分隔符 | Matcher.find() 手動構建 | split 無法保留分隔符 |
| 簡單替換 | String.replaceAll() | 一行代碼 |
| 替換邏輯複雜/需動態計算 | Matcher.appendReplacement | 可編程控制替換內容 |
| 大文本流式處理 | Matcher.appendReplacement/tail | 避免全量字符串拷貝 |
Pattern:線程安全,不可變,可作為 static final 共享。Matcher:非線程安全,有狀態,不可共享,每線程創建或用 ThreadLocal。Pattern.asMatchPredicate() / asPredicate()
Predicate isEmail = Pattern.compile(EMAIL_REGEX).asMatchPredicate();
List emails = inputs.stream().filter(isEmail).collect(toList());
// Stream 配合正則
Stream lines = Files.lines(path);
lines.flatMap(line -> Pattern.compile("\\s+").splitAsStream(line))
.filter(word -> word.length() > 3)
.collect(toList());
Java 正則三大操作——匹配驗證提取、切割分割、替換重組——覆蓋 90% 文本處理需求。掌握 Pattern/Matcher 核心 API、分組回引用、前瞻後顧、split limit 語義、appendReplacement 流式替換,並堅守預編譯復用、防災難性回溯、線程隔離 Matcher三大效能鐵律,即可寫出高效、健壯、可維護的正則代碼。複雜結構化文本(JSON、XML、HTML)請勿用正則硬解析,改用專用解析器。