Dấu hỏi ? trong regex có 3 ý nghĩa khác nhau tùy ngữ cảnh.
1. Quantifier: 0 hoặc 1 lần (Optional)
Áp dụng cho element ngay trước nó.
import re
# 'ab?c' khớp 'ac' (b: 0 lần) hoặc 'abc' (b: 1 lần)
print(bool(re.match(r'ab?c', 'ac'))) # True
print(bool(re.match(r'ab?c', 'abc'))) # True
print(bool(re.match(r'ab?c', 'abbc'))) # False
2. Non-greedy Modifier: Làm quantifier trở thành "lười biếng"
Đặt sau *, +, ?, {m,n} để match ít nhất có thể.
text = 'content1 content2 '
# Greedy (mặc định): match nhiều nhất có thể
print(re.findall(r'.* ', text))
# ['content1 content2 ']
# Non-greedy (lazy): match ít nhất có thể
print(re.findall(r'.*? ', text))
# ['content1 ', 'content2 ']
3. Group Syntax Extensions (trong ngoặc)
| Syntax | Tên | Chức năng |
|---|---|---|
(?:...) | Non-capturing group | Group không capture |
(?=...) | Positive lookahead | Assert tiếp theo khớp... |
(?!...) | Negative lookahead | Assert tiếp theo KHÔNG khớp... |
(?<=...) | Positive lookbehind | Assert trước đó khớp... |
(? | Negative lookbehind | Assert trước đó KHÔNG khớp... |
(?P | Named group | Đặt tên group |
(?P=name) | Named backreference | Tham chiếu named group |
(?(id/name)yes|no) | Conditional | If group matched thì yes else no |
(?#...) | Comment | Comment trong pattern |
(?imsx) | Inline flags | Bật/tắt flags cục bộ |
Tóm tắt 3 vai trò của ?
- Quantifier:
a?- 'a' xuất hiện 0 hoặc 1 lần. - Non-greedy modifier:
.*?,.+?,{2,5}?- match tối thiểu. - Group syntax marker:
(?...- bắt đầu special group (lookahead, named, non-capturing...).