正則表達式是字符串模式匹配的利器,從 Perl 起家現已成主流語言標配。雖語法看似晦澀,掌握核心元字符與常用模式後,能大幅提升文本處理效率。本文系統整理 Java 正則核心語法、實用模式庫與測試範例,作為開發隨手查閱手冊。
一、 核心元字符速查表
| 元字符 | 說明 | 範例 |
. | 匹配任意單字符(換行符除外) | r.t 匹配 rat、rut、r t,不匹配 root |
$ | 匹配行結尾 | weasel$ 匹配 "He's a weasel" 結尾 |
^ | 匹配行開頭 | ^When in 匹配字符串開頭 |
* | 匹配前一字符 0 次或多次 | .* 匹配任意字符序列 |
\ | 轉義符,將元字符視為普通字符 | \$ 匹配 $ 符號,\. 匹配點號 |
[ ] | 字符集合,匹配括號內任一字符 | r[aou]t 匹配 rat/rot/rut |
[c1-c2] | 字符範圍 | [0-9] 數字,[A-Za-z] 字母 |
[^c1-c2] | 排除字符集(補集) | [^269A-Z] 非 2、6、9、大寫字母 |
\< \> | 單詞邊界(非所有引擎支援) | \<the 匹配單詞開頭 the |
\( \) | 分組捕獲,最多 9 組,用 \1~\9 反向引用 | (ab)\1 匹配 abab |
| | 邏輯或 | him|her 匹配 him 或 her |
+ | 匹配前一字符 1 次或多次 | 9+ 匹配 9、99、999 |
? | 匹配前一字符 0 次或 1 次 | ab?c 匹配 ac 或 abc |
\{i\} | 精確匹配 i 次 | A[0-9]\{3\} 匹配 A123 |
\{i,j\} | 匹配 i 到 j 次 | [0-9]\{4,6\} 匹配 4-6 位數字 |
二、 Java 常用實用模式庫
字符類別與編碼
- 中文字符:
[\u4e00-\u9fa5]
- 雙字節字符(含漢字):
[^\x00-\xff](雙字節長度計 2,ASCII 計 1)
- 空白行:
\n\s*\r
常見業務驗證模式
| 場景 | 正則表達式 | 說明 |
| 手機號(舊段) | ^(1[358][0-9]{1})[0-9]{8}$ | 13/15/18 開頭 11 位 |
| HTML 標籤(部分) | <(\S*?)[^>]*>.*?</\1>|<.*? /> | 簡易匹配,嚴謹解析請用 Jsoup |
| 首尾空白 | ^\s*|\s*$ | 去除頭尾空格 |
| Email | \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* | 通用郵箱格式 |
| URL | [a-zA-z]+://[^\s]* | 協議開頭 |
| 賬號(字母開頭,5-16 位,字母數字下劃線) | ^[a-zA-Z][a-zA-Z0-9_]{4,15}$ | 註冊驗證常用 |
| 國內電話 | \d{3}-\d{8}|\d{4}-\d{7} | 區號-號碼 |
| QQ 號 | [1-9][0-9]{4,} | 5 位起,非 0 開頭 |
| 郵政編碼 | [1-9]\d{5}(?!\d) | 6 位,非 0 開頭 |
| 身份證(簡易) | \d{15}|\d{18} | 僅長度校驗,嚴格需加權校驗碼 |
| IPv4 | \d+\.\d+\.\d+\.\d+ | 簡易版,嚴格需限制 0-255 |
數字範圍專用模式
- 正整數:
^[1-9]\d*$
- 負整數:
^-[1-9]\d*$
- 整數:
^-?[1-9]\d*$
- 非負整數:
^[1-9]\d*|0$
- 非正整數:
^-[1-9]\d*|0$
- 正浮點數:
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$
- 負浮點數:
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$
- 浮點數:
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
- 非負浮點數:
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
- 非正浮點數:
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
特定字符串模式
- 純英文字母:
^[A-Za-z]+$
- 純大寫:
^[A-Z]+$
- 純小寫:
^[a-z]+$
- 字母數字:
^[A-Za-z0-9]+$
- 字母數字下劃線:
^\w+$
三、 Java 代碼測試範例
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
// 驗證正整數
String regex = "^[1-9]\\d*$";
System.out.println(Pattern.matches(regex, "1213")); // true
System.out.println(Pattern.matches(regex, "0")); // false
System.out.println(Pattern.matches(regex, "-5")); // false
System.out.println(Pattern.matches(regex, "abc")); // false
// 複雜模式:提取 Email 域名
String email = "user.name+tag@sub.domain.com";
Pattern p = Pattern.compile("@(.+)$");
java.util.regex.Matcher m = p.matcher(email);
if (m.find()) {
System.out.println("Domain: " + m.group(1)); // sub.domain.com
}
}
}
四、 進階技巧與避坑指南
- 預編譯複用:高頻調用時使用
Pattern.compile() 緩存編譯結果,避免重複編譯開銷。
- 貪婪 vs 非貪婪:
.* 為貪婪匹配盡可能多,.*? 為非貪婪匹配盡可能少,HTML 解析常用非貪婪。
- 邊界斷言:
\b 匹配單詞邊界,\B 非單詞邊界,比 \<\> 兼容性更好。
- Pattern.CASE_INSENSITIVE:忽略大小寫編譯標誌,避免在模式中寫
(?i)。
- 分組命名 (Java 7+):
(?<name>...) 命名捕獲組,matcher.group("name") 讀取,提升可讀性。
- 性能陷阱:避免嵌套量詞(如
(a*)*)導致災難性回溯,長文本處理考慮具體化模式或使用非正則方案。