Named Groups cho phép đặt tên cho capturing group, thay vì dùng chỉ số (1, 2, 3...). Cú pháp: (?P<name>pattern). Tham chiếu sau: (?P=name).
Vấn đề của numbered groups
- Regex dài, nhiều group → khó nhớ số thứ tự.
- Thêm/xóa group ở giữa → lệch toàn bộ số thứ tự sau đó.
Cú pháp Named Groups
(?Ppattern) # Capture group tên 'name'
(?P=name) # Backreference đến group 'name'
name: bắt đầu bằng chữ cái, chỉ chứa alphanumeric + underscore.pattern: bất kỳ regex hợp lệ nào.
Ví dụ: Parse HTML tag
import re
# Không đặt tên: khó hiểu \1, \2 là gì
pattern1 = r'<([A-Z][A-Z0-9]*)\b[^>]*>.*?\1>'
# Đặt tên: rõ ràng, dễ bảo trì
pattern2 = r'<(?P[A-Z][A-Z0-9]*)\b[^>]*>.*?(?P=tag)>'
html = 'Content'
match = re.search(pattern2, html)
if match:
print(match.group('tag')) # 'DIV' - truy cập bằng tên
print(match.group(1)) # 'DIV' - vẫn truy cập bằng số được
Truy cập Named Groups
match = re.search(r'(?P\d{4})-(?P\d{2})-(?P\d{2})', '2024-01-15')
# Bằng tên (khuyến nghị)
print(match.group('year')) # '2024'
print(match.group('month')) # '01'
print(match.group('day')) # '15'
# Bằng số (vẫn hoạt động)
print(match.group(1, 2, 3)) # ('2024', '01', '15')
# Dictionary tất cả named groups
print(match.groupdict()) # {'year': '2024', 'month': '01', 'day': '15'}
# Dùng trong substitution
re.sub(r'(?P\d{4})-(?P\d{2})', r'\g/\g', '2024-01')
# '01/2024'
Lợi ích
- Code tự tài liệu (self-documenting).
- Thêm/xóa group không ảnh hưởng group khác.
- Dễ debug:
match.groupdict()xem tất cả. - Substitution rõ ràng:
\g.