在 Java 正則表達式的世界裡,數量詞的匹配模式直接決定了匹配的行為與效能。貪婪、勉強、獨占這三種模式雖然語法相近,但其底層機制卻大相徑庭。本文將透過詳細的對比表格、實戰代碼與輸出分析,帶你徹底掌握它們的區別與應用場景。
| 數量詞 | 貪婪 | 勉強 | 獨占 | 匹配含義 |
|---|---|---|---|---|
| X? | X? | X?? | X?+ | X,一次或零次 |
| X* | X* | X*? | X*+ | X,零次或多次 |
| X+ | X+ | X+? | X++ | X,一次或多次 |
| X{n} | X{n} | X{n}? | X{n}+ | X,恰好 n 次 |
| X{n,} | X{n,} | X{n,}? | X{n,}+ | X,至少 n 次 |
| X{n,m} | X{n,m} | X{n,m}? | X{n,m}+ | X,至少 n 次,但不超過 m 次 |
術語對照: Greedy(貪婪)、Reluctant(勉強)、Possessive(獨占)。
package jichu;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MainClass {
public static void main(String[] args) {
Matcher m1 = Pattern.compile("\\w+").matcher("ababa"); // 貪婪
Matcher m2 = Pattern.compile("\\w+?").matcher("ababa"); // 勉強
Matcher m3 = Pattern.compile("\\w++").matcher("ababa"); // 獨占
System.out.println(piPei(m1));
System.out.println(piPei(m2));
System.out.println(piPei(m3));
}
public static String piPei(Matcher m) {
StringBuffer s = new StringBuffer();
int i = 0;
while (m.find()) {
s.append("{匹配子串" + ++i + ":" + m.group() + ";");
s.append("起始位置:" + m.start() + ";");
s.append("結束位置:" + m.end() + ";}");
}
if (s.length() == 0) {
s.append("沒有匹配到!");
}
s.insert(0, "(模式" + m.pattern().pattern() + "):");
return s.toString();
}
}
(模式\w+):{匹配子串1:ababa;起始位置:0;結束位置:5;}
(模式\w+?):{匹配子串1:a;起始位置:0;結束位置:1;}{匹配子串2:b;起始位置:1;結束位置:2;}{匹配子串3:a;起始位置:2;結束位置:3;}{匹配子串4:b;起始位置:3;結束位置:4;}{匹配子串5:a;起始位置:4;結束位置:5;}
(模式\w++):{匹配子串1:ababa;起始位置:0;結束位置:5;}
ababa。在測試一基礎上修改正則,尾部加上字符 b:
public static void main(String[] args) {
Matcher m1 = Pattern.compile("\\w+b").matcher("ababa"); // 貪婪
Matcher m2 = Pattern.compile("\\w+?b").matcher("ababa"); // 勉強
Matcher m3 = Pattern.compile("\\w++b").matcher("ababa"); // 獨占
System.out.println(piPei(m1));
System.out.println(piPei(m2));
System.out.println(piPei(m3));
}
(模式\w+b):{匹配子串1:abab;起始位置:0;結束位置:4;}
(模式\w+?b):{匹配子串1:ab;起始位置:0;結束位置:2;}{匹配子串2:ab;起始位置:2;結束位置:4;}
(模式\w++b):沒有匹配到!
\w+ 先吞噬整個 ababa,發現後面無法匹配 b,於是回溯吐出一個字符 a,剩餘 abab 成功匹配 b。\w+? 逐字符嘗試,a 不匹配 b,ab 匹配成功;繼續掃描,再次匹配 ab,共兩次匹配。\w++ 一次性吞噬 ababa,後面無法匹配 b,拒絕回溯,直接宣告匹配失敗。| 模式 | 特性 | 回溯 | 適用場景 |
|---|---|---|---|
| 貪婪 | 盡可能多匹配,預設行為 | 支援 | 通用匹配,需配合後續模式時利用回溯 |
| 勉強 | 盡可能少匹配,非貪婪 | 支援 | 需最小匹配範圍,如 HTML 標籤內容提取 <.+?> |
| 獨占 | 盡可能多匹配,但鎖死不回溯 | 不支援 | 效能優化、避免災難性回溯、明確不需回溯的場景 |
關鍵洞見: 獨占模式通過犧牲回溯能力換取確定性與效能,在處理大量數據或複雜正則時能有效防止災難性回溯導致的效能崩潰。
更多正則表達式相關內容: