Khi xây dựng biểu thức chính quy, nếu cần chỉ định số lần xuất hiện của một mẫu, ta sử dụng quantifier (lượng từ). Java hỗ trợ 3 loại quantifier chính:
- Greedy (Tham lam) - Mặc định
- Reluctant / Non-greedy (Ngại ngùng / Không tham lam)
- Possessive (Hưu đãi / Độc chiếm)
1. Greedy Quantifiers (Mặc định)
Khớp nhiều nhất có thể (longest match). Nếu không khớp toàn bộ, nó backtrack (lùi lại) bỏ bớt ký tự cuối và thử lại.
| Ký hiệu | Ý nghĩa |
|---|---|
X? | 0 hoặc 1 lần |
X* | 0 hoặc nhiều lần |
X+ | 1 hoặc nhiều lần |
X{n} | Đúng n lần |
X{n,} | Ít nhất n lần |
X{n,m} | Từ n đến m lần |
Ví dụ: [0-9]+ (Greedy)
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Nhập văn bản:");
String input = sc.nextLine();
String regex = "[0-9]+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
System.out.println("Văn bản khớp:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
Kết quả
Nhập văn bản: abc123def456 Văn bản khớp: 123 456
2. Reluctant Quantifiers (Non-greedy)
Khớp ít nhất có thể. Ban đầu khớp 1 ký tự, nếu thất bại thì thêm ký tự tiếp theo. Được tạo bằng cách thêm ? sau greedy quantifier.
| Greedy | Reluctant |
|---|---|
X* | X*? |
X+ | X+? |
X? | X?? |
X{n,} | X{n,}? |
X{n,m} | X{n,m}? |
Ví dụ: [0-9]+? (Reluctant)
String regex = "[0-9]+?";
// Input: 12345678
// Output: 1 2 3 4 5 6 7 8 (mỗi số 1 dòng)
Kết quả
Nhập văn bản: 12345678 1 2 3 4 5 6 7 8
3. Possessive Quantifiers
Tương tự greedy (khớp nhiều nhất), nhưng KHÔNG backtrack. Nếu khớp thất bại, nó dừng lại ngay, không thử lùi lại. Tạo bằng cách thêm + sau greedy quantifier.
| Greedy | Possessive |
|---|---|
X* | X*+ |
X+ | X++ |
X? | X?+ |
X{n,} | X{n,}+ |
X{n,m} | X{n,m}+ |
Ví dụ: [0-9]++ (Possessive)
String regex = "[0-9]++";
// Input: 45678
// Output: 45678 (khớp toàn bộ, không backtrack)
Kết quả
Nhập văn bản: 45678 45678
Bảng so sánh hành vi
| Loại | Ký hiệu | Chiến lược | Backtrack? | Hiệu năng khi thất bại |
|---|---|---|---|---|
| Greedy | X*, X+ | Khớp max, rồi lùi dần | Có | Chậm nếu pattern phức tạp thất bại |
| Reluctant | X*?, X+? | Khớp min, rồi mở rộng dần | Có | Chậm nếu phải mở rộng nhiều lần |
| Possessive | X*+, X++ | Khớp max, không lùi | Không | Nhanh khi thất bại (fail-fast) |
Khi nào dùng loại nào?
- Greedy: Mặc định, phù hợp đa số trường hợp đơn giản.
- Reluctant: Khi cần khớp ngắn nhất (ví dụ: khớp thẻ HTML
<.+?>thay vì<.+>). - Possessive: Tối ưu hiệu năng, tránh catastrophic backtracking trên pattern phức tạp (ví dụ:
[0-9]++thay vì[0-9]+khi biết chắc chuỗi chỉ toàn số).