自 JDK 1.4 引入 java.util.regex 套件,Java 終於擁有原生、強大且標準化的正則表達式引擎。本文從核心類別 Pattern、Matcher 切入,系統講解語法元素、分組捕獲、貪婪/勉強模式、常用實戰範例(電話號碼、Email、HTML 標籤),並提供效能優化與避坑指南。
Pattern.compile(regex) 取得。pattern.matcher(input) 取得,非執行緒安全。import java.util.regex.*;
public class RegexDemo {
public static void main(String[] args) {
// 1. 編譯模式(建議複用 Pattern 實例)
Pattern pattern = Pattern.compile("\\(\\d{3}\\)\\s?\\d{3}-\\d{4}");
// 2. 取得匹配器
Matcher matcher = pattern.matcher("(212) 555-1212");
// 3. 執行匹配
if (matcher.find()) {
System.out.println("完整匹配: " + matcher.group()); // (212) 555-1212
System.out.println("第1組: " + matcher.group(1)); // 若有捕獲組
}
// 4. 替換操作
String replaced = matcher.replaceAll("[PHONE]");
}
}
| 分類 | 符號 | 說明 | 範例 |
|---|---|---|---|
| 字元類別 | . | 任意單一字元(預設不含換行) | a.c 匹配 abc, axc |
\d | 數字 [0-9] | \d{3} 三位數 | |
\D | 非數字 | ||
\s | 空白字元(空格、Tab、換行) | ||
\S | 非空白 | ||
[abc] / [^abc] | 字元集合 / 排除集合 | [aeiou] 母音 | |
| 數量詞 | ? | 0 或 1 次 | \d? |
* | 0 或多次(貪婪) | ab*c 匹配 ac, abc, abbc... | |
+ | 1 或多次(貪婪) | ||
{n,m} | n 到 m 次 | \d{3,5} | |
| 邊界 | ^ | 行首(多行模式 Pattern.MULTILINE) | |
$ | 行尾 | ||
\b | 單字邊界 | \bcat\b 不匹配 "catfish" | |
| 分組與引用 | (...) | 捕獲組,可用 group(i) 取得 | (\d{4})-(\d{2}) |
(?:...) | 非捕獲組(僅分組不儲存) | (?:\d{3})?- | |
\1, \2... | 反向引用(匹配前面第 n 組內容) | (\w+)\s+\1 匹配重複單字 | |
| 模式修飾符 | Pattern.CASE_INSENSITIVE | 忽略大小寫 | Pattern.compile("abc", Pattern.CASE_INSENSITIVE) |
Pattern.MULTILINE | ^$ 匹配行首尾 | ||
Pattern.DOTALL | . 匹配含換行 |
需求:支援 (212) 555-1212、212-555-1212、212 555 1212、2125551212。
// 1. 區碼可選括號、可選空格、分隔符可為 - 或空格或無
String regex = "(\\(\\d{3}\\)|\\d{3})[\\s-]?\\d{3}[\\s-]?\\d{4}";
Pattern p = Pattern.compile(regex);
String[] tests = {
"(212) 555-1212", "212-555-1212", "212 555 1212", "2125551212",
"212-5551212", "(212)555-1212"
};
for (String s : tests) {
Matcher m = p.matcher(s);
System.out.println(s + " -> " + (m.matches() ? "匹配" : "不匹配"));
}
輸出:
(212) 555-1212 -> 匹配
212-555-1212 -> 匹配
212 555 1212 -> 匹配
2125551212 -> 匹配
212-5551212 -> 匹配
(212)555-1212 -> 匹配
matcher.group(1) 取得區碼,matcher.replaceAll("$1-$2-$3") 格式化。Pattern.compile("\\s*,\\s*").split("a, b ,c") → [a, b, c]。Pattern.quote("$1.50") 自動轉義特殊字元。(a+)+)導致災難性回溯。matcher.find() 迴圈而非 split()。| 陷阱 | 原因 | 解法 |
|---|---|---|
雙反斜線 \\\\ | Java 字串字面值需轉義,正則引擎再解析一次 | 習慣寫 \\d、\\.、\\\\;或用 Pattern.quote() |
matches() vs find() | matches() 需整串匹配,find() 尋找子串 | 全匹配用 matches(),搜尋用 find() |
| 貪婪匹配吃掉分隔符 | .* 會吞掉後續內容 | 改用勉強模式 .*? 或明確字元集 [^,]* |
| 群組索引從 1 開始 | group(0) 為整體匹配 | 捕獲組用 group(1) 起 |
Java 正則表達式功能強大且標準化,掌握 Pattern/Matcher 雙核心、熟悉語法元素與修飾符、養成預編譯與勉強模式習慣,即能輕鬆應對複雜字串解析、驗證、提取與替換需求。建議收藏本文語法速查表,實戰中隨查隨用。