一、核心類別
java.util.regex.Pattern:編譯後的正則模式(不可變、執行緒安全)
java.util.regex.Matcher:對輸入字串執行匹配的引擎(有狀態、非執行緒安全)
二、常用元字元速查表
| 類別 | 符號 | 說明 | 範例匹配 |
| 預定義字元類 | \d | 數字 [0-9] | 0-9 |
\D | 非數字 [^0-9] | a, # |
\s | 空白 [\t\n\r\f] | 空格、換行 |
\S | 非空白 | a, 1 |
\w | 單字字元 [a-zA-Z0-9_] | a, Z, 9, _ |
\W | 非單字字元 | #, @ |
. | 任意字元(除換行) | a, 1, # |
\b / \B | 單字邊界 / 非邊界 | \bcat\b 匹配 "cat" 不匹配 "category" |
| 數量詞 | * | 0 次以上 | ab*c → ac, abc, abbc |
+ | 1 次以上 | ab+c → abc, abbc |
? | 0 或 1 次 | ab?c → ac, abc |
{n} | 恰好 n 次 | a{3} → aaa |
{n,} | n 次以上 | a{2,} → aa, aaa... |
{n,m} | n 到 m 次 | a{2,4} → aa, aaa, aaaa |
| 定錨 | ^ | 行首(單行模式為字串首) | ^Java |
$ | 行尾(單行模式為字串尾) | Java$ |
\A / \Z | 字串絕對開頭/結尾(不受多行模式影響) | - |
| 分組/選擇 | () | 捕獲群組、子模式 | (ab)+ → abab |
| | | 或 | cat|dog |
三、Pattern 編譯旗標
Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
| 旗標 | 內嵌寫法 | 效果 |
CASE_INSENSITIVE | (?i) | 忽略大小寫(預設僅 ASCII,搭配 UNICODE_CASE 支援 Unicode) |
MULTILINE | (?m) | ^ $ 匹配每行開頭結尾 |
DOTALL | (?s) | . 匹配含換行的任意字元 |
COMMENTS | (?x) | 忽略模式中的空白、支援 # 註解 |
UNICODE_CASE | (?u) | Unicode 大小寫不敏感(需配合 CASE_INSENSITIVE) |
UNIX_LINES | (?d) | 只認 \n 為行結尾 |
四、Matcher 核心操作
| 方法 | 用途 | 回傳 |
matches() | 整個字串完整匹配 | boolean |
find() | 尋找下一個子序列匹配 | boolean |
group(int) | 取得捕獲群組內容(0 為整體) | String |
start()/end() | 匹配區間索引 | int |
replaceFirst(repl) | 替換第一處 | String |
replaceAll(repl) | 替換所有 | String |
appendReplacement(sb, repl) | 逐段建構替換結果 | Matcher(鏈式) |
appendTail(sb) | 補上尾部未匹配部分 | StringBuffer |
五、實戰範例集錦
1. Email 驗證
String email = "user.name@domain.com.cn";
Pattern p = Pattern.compile("[\\w\\.-]+@([\\w-]+\\.)+[\\w-]+", Pattern.CASE_INSENSITIVE);
System.out.println(p.matcher(email).matches()); // true
2. 多字元分割字串
String[] parts = Pattern.compile("[,|;;\\s]+").split("Java,Hello;World Scala");
// [Java, Hello, World, Scala]
3. 移除 HTML 標籤
String html = "<a href=\"index.html\">首頁</a>";
String text = Pattern.compile("<.+?>", Pattern.DOTALL).matcher(html).replaceAll("");
// 首頁
4. 擷取 HTML 屬性值
Matcher m = Pattern.compile("href=\"(.+?)\"").matcher(html);
if (m.find()) System.out.println(m.group(1)); // index.html
5. 擷取 URL
Matcher m = Pattern.compile("(https?://)[\\w./:-]+").matcher(text);
while (m.find()) System.out.println(m.group());
6. 佔位符替換 {0} {1}
String tpl = "Java 發展史 {0}年-{1}年";
String[][] map = {{"\\{0\\}", "1995"}, {"\\{1\\}", "2007"}};
for (String[] kv : map) {
tpl = Pattern.compile(kv[0]).matcher(tpl).replaceAll(kv[1]);
}
// Java 發展史 1995年-2007年
7. 目錄下依正則篩選檔案
File dir = new File("C:/logs");
File[] files = dir.listFiles((d, name) -> Pattern.matches("\\d{4}-\\d{2}-\\d{2}\\.log", name));
// 2024-01-15.log 等
六、效能與最佳實踐
- 預編譯 Pattern:靜態常量或單例持有,避免重複編譯。
- 善用
find() 迴圈:比 matches() 靈活,支援逐個處理。
- 非貪婪量詞
*? +?:避免過度回溯導致效能災難(ReDoS)。
- 複雜正則拆解:用
COMMENTS 旗標加入註解與空白,提升可讀性。
- 輸入長度限制:防止惡意長字串耗盡 CPU。
七、總結
Java 正則引擎功能強大,掌握 Pattern/Matcher API、常用元字元、旗標與實戰慣用模式,即可輕鬆應對驗證、解析、清洗、轉換等文字處理需求。記住:預編譯、非貪婪、限長度 三大原則,寫出高效能、安全的正則代碼。