JDK 7 (b50+) 正式支援 `(?
| 功能 | 語法 | 範例 | 說明 |
|---|---|---|---|
| 定義命名群組 | `(? | `(? | 名稱限制:字母開頭、字母數字底線、不以數字結尾 |
| 正則內反向引用 | `\k | `(?['"]).*?\k` | 匹配同名群組捕獲的內容 |
| 替換字串引用 | `$ | `$ | `Matcher.replaceFirst/All`、`String.replaceFirst/All` 使用 |
| Matcher API 取值 | `matcher.group("NAME")` | `m.group("year")` | 直接按名稱取得,無需記憶編號 |
| Matcher API 索引 | `matcher.group(int group)` | `m.group(1)` | 傳統編號方式仍支援 (命名群組也有隱含編號) |
String log = "2024-03-15 14:30:45 [ERROR] com.payment.service - Transaction failed: id=TXN12345, amount=99.99";
String regex = "(?\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[(?\\w+)\\] (?[\\w.]+) - (?.+)";
Pattern pattern = Pattern.compile(regex);
Matcher m = pattern.matcher(log);
if (m.matches()) {
System.out.println("時間: " + m.group("timestamp"));
System.out.println("等級: " + m.group("level"));
System.out.println("Logger: " + m.group("logger"));
System.out.println("訊息: " + m.group("message"));
// 依然可以用編號
System.out.println("群組 1 (時間): " + m.group(1));
}
String html = "內容文字";
// 簡易版:捕獲標籤名,反向引用閉合標籤
String regex = "<(?\\w+)[^>]*>.*?\\k>";
Pattern p = Pattern.compile(regex, Pattern.DOTALL);
Matcher m = p.matcher(html);
while (m.find()) {
System.out.println("完整標籤: " + m.group());
System.out.println("標籤名: " + m.group("tag"));
}
String input = "日期: 2024/03/15";
String regex = "(?\\d{4})/(?\\d{2})/(?\\d{2})";
String replacement = "${d}-${m}-${y}"; // 或 $-$-$
String output = input.replaceFirst(regex, replacement);
System.out.println(output); // 日期: 15-03-2024
需分組量詞但不想佔用編號/命名:
// 匹配 IP,只捕獲最後一段
String regex = "(?:\\d{1,3}\\.){3}(?\\d{1,3})";
**注意**:Java **不支援** `(?|...)` (PCRE/Go/Perl 支援)。Java 中各分支群組編號獨立,命名群組在不同分支**不可同名**,否則編譯錯誤。
命名群組**同時擁有隱含編號** (按左括號順序)。`group("name")` 等價 `group(index)`。建議**統一使用名稱** 避免混淆。
String regex = "(?x) # 開啟註解模式\n" +
"(? \\d{4} ) - # 年份\n" +
"(? \\d{2} ) - # 月份\n" +
"(? \\d{2} ) # 日期";
命名捕獲組是 Java 正則表達式**可讀性、維護性、錯誤率**的質變升級。掌握 `(?