正則量詞決定「匹配多少次」,Java 提供三種模式,行為差異巨大,掌握它們是寫出高性能、正確正則的關鍵。
| 匹配次數 | 貪婪 | 勉強 | 獨占 |
|---|---|---|---|
| 0 或 1 | X? | X?? | X?+ |
| 0 或多 | X* | X*? | X*+ |
| 1 或多 | X+ | X+? | X++ |
| 恰好 n | X{n} | X{n}? | X{n}+ |
| 至少 n | X{n,} | X{n,}? | X{n,}+ |
| n 到 m | X{n,m} | X{n,m}? | X{n,m}+ |
public class QuantifierDemo {
public static void main(String[] args) {
String text = "ababa";
test("\\w+", text, "貪婪 \\w+");
test("\\w+?", text, "勉強 \\w+?");
test("\\w++", text, "獨占 \\w++");
System.out.println("--- 加上尾部 b ---");
test("\\w+b", text, "貪婪 \\w+b");
test("\\w+?b", text, "勉強 \\w+?b");
test("\\w++b", text, "獨占 \\w++b");
}
static void test(String regex, String text, String label) {
Matcher m = Pattern.compile(regex).matcher(text);
System.out.print(label + " => ");
while (m.find()) {
System.out.printf("[%d-%d:%s] ", m.start(), m.end(), m.group());
}
System.out.println();
}
}
貪婪 \w+ => [0-5:ababa] 勉強 \w+? => [0-1:a] [1-2:b] [2-3:a] [3-4:b] [4-5:a] 獨占 \w++ => [0-5:ababa] --- 加上尾部 b --- 貪婪 \w+b => [0-4:abab] // \w+ 先吞全串,回溯 1 字符匹配 b 勉強 \w+?b => [0-2:ab] [2-4:ab] // 每次最少匹配 1 個字符再試 b 獨占 \w++b => (無匹配) // \w++ 吞全串,無回溯,b 匹配失敗整體失敗
\d++ 匹配純數字串,明確後面不可能是數字,獨占避免回溯開銷,防止 ReDoS。".*?",但慎用於大文本,可能導致大量嘗試,優於貪婪回溯但仍有性能隱患。.、\w,如 [^"]* 替代 ".*?",從根源消除回溯。更多內容:Java 正則規則表 | Pattern 類詳解 | Matcher 類詳解