一、String 類內建正則方法
| 方法 | 說明 | 回傳值 |
matches(regex) | 整串字串是否符合正則 | boolean |
replaceAll(regex, replacement) | 替換所有符合的子字串 | String |
split(regex) | 依正則分割字串 | String[] |
replaceFirst(regex, replacement) | 替換第一個符合的子字串 | String |
二、核心 API:Pattern 與 Matcher
// 編譯模式(建議複用 Pattern,執行緒安全)
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
// 建立匹配器(非執行緒安全,每次匹配新建)
Matcher matcher = pattern.matcher(input);
// 常用操作
boolean matches = matcher.matches(); // 整串匹配
boolean find = matcher.find(); // 尋找下一個匹配
String group = matcher.group(); // 完整匹配內容
String group1 = matcher.group(1); // 第 1 組捕獲
int start = matcher.start(); // 匹配起始索引
int end = matcher.end(); // 匹配結束索引
String replaced = matcher.replaceAll(repl); // 全部替換
StringBuffer sb = new StringBuffer();
while (matcher.find()) matcher.appendReplacement(sb, repl);
matcher.appendTail(sb); // 手動構建替換結果
三、正則語法速查表
1. 字元類別
| 語法 | 匹配內容 |
. | 任意字元(除換行符,除非開啟 DOTALL) |
\d | 數位 [0-9] |
\D | 非數位 |
\s | 空白字元(空格、\t、\n、\r、\f) |
\S | 非空白字元 |
\w | 單字字元 [a-zA-Z0-9_] |
\W | 非單字字元 |
2. 量詞
| 貪婪 | 懶惰 | 佔有優先 | 說明 |
* | *? | *+ | 0 次或多次 |
+ | +? | ++ | 1 次或多次 |
? | ?? | ?+ | 0 次或 1 次 |
{n} | - | - | 恰好 n 次 |
{n,} | {n,}? | - | 至少 n 次 |
{n,m} | {n,m}? | - | n 到 m 次 |
3. 邊界與斷言
| 語法 | 名稱 | 匹配位置 |
^ | 行首 | 字串開頭(MULTILINE 時每行開頭) |
$ | 行尾 | 字串結尾(MULTILINE 時每行結尾) |
\b | 單字邊界 | \w 與 \W 交界 |
\B | 非單字邊界 | \w-\w 或 \W-\W 交界 |
(?=X) | 正向前瞻 | 後面是 X(不消耗字元) |
(?!X) | 負向前瞻 | 後面不是 X |
(?<=X) | 正向後顧 | 前面是 X(固定寬度) |
(? | 負向後顧 | 前面不是 X |
四、實戰範例
1. 驗證手機號(中國大陸)
String regex = "^1[3-9]\\d{9}$";
boolean valid = Pattern.matches(regex, "13812345678"); // true
2. 提取 HTML 標籤屬性
String html = "
";
Pattern p = Pattern.compile("
]*src=['\"]([^'\"]+)['\"]");
Matcher m = p.matcher(html);
while (m.find()) System.out.println(m.group(1)); // logo.png
3. 分割保留分隔符
String[] parts = "Java,Python;Go".split("(?=[,;])|(?<=[,;])");
// 結果: ["Java", ",", "Python", ";", "Go"]
4. 密碼強度驗證(8-20 位,含大小寫、數字、特殊符號)
String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*]).{8,20}$";
五、效能優化與避坑
- 預編譯 Pattern:靜態常量或快取,避免重複編譯
- 避免災難性回溯:
(a+)+ 匹配 aaaaaaaaaaaaab 會指數級回溯,改用佔有優先 (a++)+ 或原子群 (?>a+)+
- 具體化字元類別:
.* → [^"\r\n]* 減少回溯
- 善用非捕獲群:
(?:group) 不佔用群組編號、較快
- 大文本用 find() 迭代:而非一次性
matches()