首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 正則表達式命名捕獲組完整指南:JDK 7+ 新語法、反向引用、替換、Matcher API 實戰

     編輯:Java 相關知識

背景:JDK 7 引入命名捕獲組

JDK 7 (b50+) 正式支援 `(?...)` 命名捕獲組,解決「數組編號難維護、可讀性差、修改正則導致群組編號漂移」痛點。現代 Java (JDK 8/11/17/21) 完整支援。

核心語法速查表

功能語法範例說明
定義命名群組`(?pattern)``(?\d{4})`名稱限制:字母開頭、字母數字底線、不以數字結尾
正則內反向引用`\k``(?['"]).*?\k`匹配同名群組捕獲的內容
替換字串引用`$` 或 `${NAME}``$-$``Matcher.replaceFirst/All`、`String.replaceFirst/All` 使用
Matcher API 取值`matcher.group("NAME")``m.group("year")`直接按名稱取得,無需記憶編號
Matcher API 索引`matcher.group(int group)``m.group(1)`傳統編號方式仍支援 (命名群組也有隱含編號)

實戰範例 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));
}

實戰範例 2:HTML 標籤配對 (反向引用)


String html = "
內容
文字"; // 簡易版:捕獲標籤名,反向引用閉合標籤 String regex = "<(?\\w+)[^>]*>.*?>"; 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")); }

實戰範例 3:日期格式轉換 (替換引用)


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

進階技巧

1. 非捕獲群組 `(?:...)` 配合命名群組

需分組量詞但不想佔用編號/命名:


// 匹配 IP,只捕獲最後一段
String regex = "(?:\\d{1,3}\\.){3}(?\\d{1,3})";

2. 分支重置 `(?|...)` — 同名群組在不同分支 (JDK 不支援!)

**注意**:Java **不支援** `(?|...)` (PCRE/Go/Perl 支援)。Java 中各分支群組編號獨立,命名群組在不同分支**不可同名**,否則編譯錯誤。

3. 具名群組與 `group(int)` 編號關係

命名群組**同時擁有隱含編號** (按左括號順序)。`group("name")` 等價 `group(index)`。建議**統一使用名稱** 避免混淆。

4. 多行/註解模式 `(?x)` 提升可讀性


String regex = "(?x)               # 開啟註解模式\n" +
    "(?  \\d{4} )  -  # 年份\n" +
    "(? \\d{2} )  -  # 月份\n" +
    "(?   \\d{2} )     # 日期";

效能與最佳實踐

  • 預編譯 Pattern:`Pattern` 執行緒安全,**靜態常量** 重用,避免重複編譯正則。
  • 避免過度捕獲:不需提取的群組用 `(?:...)` 非捕獲,減少記憶體/回溯開銷。
  • 具名群組微小開銷:內部維護名稱→索引映射,極微影響,換取巨大可讀性/維護性收益,**強烈建議生產代碼全面採用**。
  • 正則注入防禦:用戶輸入拼入正則前,必須 `Pattern.quote(input)` 轉義元字符。

總結

命名捕獲組是 Java 正則表達式**可讀性、維護性、錯誤率**的質變升級。掌握 `(?)`, `\k`, `$`, `group("name")` 四大核心語法,配合預編譯、非捕獲群組、註解模式,即可編寫專業級、可長期維護的正則解析邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved