Java 生態存在多種正則引擎:Jakarta ORO、Jakarta Regexp、GNU Regexp、JDK 1.4+ java.util.regex。直接依賴某庫導致:代碼耦合、遷移成本高、無法對比性能。引入抽象層 RegexpPlugin,定義統一接口,通過適配器模式接入不同引擎,實現編譯期解耦、運行期熱插拔、基準測試驅動選型。
| 接口 | 職責 | 對應概念 |
|---|---|---|
Compiler | 編譯模式串為 Pattern | ORO: Perl5Compiler, JDK: Pattern.compile() |
Pattern | 編譯後的正則模式 (不可變、可重用) | ORO: Pattern, JDK: Pattern |
Matcher | 執行匹配操作,保持狀態 | ORO: Perl5Matcher, JDK: Matcher |
MatchResult | 單次匹配結果,提供分組提取 | ORO: MatchResult, JDK: Matcher (兼作結果) |
RegexpManager | 工廠類,創建 Compiler/Matcher 實例 | 隱藏具體適配器實例化邏輯 |
// 正則: .*\s*(.*?)\s+.* (取第一個空格前的詞)
// 1. 獲取編譯器 (拋出 RegexpEngineNotFoundException 需捕獲)
Compiler compiler = RegexpManager.createCompiler(); // 默認 ORO, 可配置
compiler.setMultiline(true); // 支持通用標志: 大小寫、多行
Pattern pattern = compiler.compile(".*\\s*(.*?)\\s+.*");
// 2. 獲取匹配器
Matcher matcher = RegexpManager.createMatcher();
// 3. 匹配並提取
if (matcher.contains("John A. Smith", pattern)) {
MatchResult result = matcher.getMatch();
String name = result.group(1); // 獲取第1組 -> "John"
// 循環匹配所有: while (matcher.contains(...)) { ... }
}
| 概念 | GNU Regexp 1.2 | Jakarta ORO 2.0.6 | Jakarta Regexp 1.3 | JDK 1.4+ |
|---|---|---|---|---|
| Compiler | gnu.regexp.RE | org.apache.oro.text.regex.Perl5Compiler | org.apache.regexp.RECompiler | java.util.regex.Pattern |
| Pattern | gnu.regexp.RE | org.apache.oro.text.regex.Pattern | org.apache.regexp.REProgram | java.util.regex.Pattern |
| Matcher | gnu.regexp.REMatchEnumeration | org.apache.oro.text.regex.Perl5Matcher | org.apache.regexp.RE | java.util.regex.Matcher |
| MatchResult | gnu.regexp.REMatch | org.apache.oro.text.regex.MatchResult | org.apache.regexp.RE | java.util.regex.Matcher |
| 異常 | gnu.regexp.REException | org.apache.oro.text.regex.MalformedPatternException | org.apache.regexp.RESyntaxException | java.util.regex.PatternSyntaxException |
若客戶代碼需使用特定引擎獨有功能 (如 ORO 的 EXTENDED_MASK),API 可拋出 UnsupportedOperationException 或引入責任鏈:請求對象攜帶功能標識,鏈上各適配器嘗試處理,不支持則傳遞下一個。
內建基準工具解析 HTML 頁面 10,000 次 (含鏈接、表單、表格提取),測試環境相同:
| 引擎 | 耗時 (秒) | 相對性能 |
|---|---|---|
| Jakarta ORO 2.0.6 | 130.71 | 基準 |
| Jakarta Regexp 1.2 | 23.26 | **5.6x 快** |
| GNU Regexp 1.1.4 | 1966.94 | 極慢 |
| JDK 1.4 java.util.regex | 33.22 | 3.9x 快 |
結論:JDK 內置引擎性能優異且零依賴,應為首選。ORO 功能豐富但較慢。RegexpPlugin 使此類對比零成本可行。
Pattern 不可變,靜態字段緩存,避免重複編譯開銷。RegexpEngineNotFoundException 降級或報警。CASE_INSENSITIVE/MULTILINE,保證可移植。