Bảng tóm tắt Regex miễn phí
Hướng dẫn tham khảo tương tác cho biểu thức chính quy.
Kiểm tra mẫu
Cách sử dụng
- Duyệt qua các danh mục mẫu hoặc sử dụng thanh tìm kiếm để tìm một mẫu cụ thể.
- Nhập một biểu thức chính quy vào ô « Kiểm tra mẫu » và văn bản mẫu vào « Văn bản kiểm tra ».
- Bật/tắt các cờ (toàn cục, không phân biệt hoa thường, đa dòng) và xem các kết quả khớp được tô sáng tức thì.
Câu hỏi thường gặp
Biểu thức chính quy là gì?
Biểu thức chính quy (regex hoặc regexp) là một mẫu được sử dụng để tìm kiếm, truy xuất và thay thế văn bản. Nó sử dụng các ký tự đặc biệt và cú pháp để xác định các chuỗi cần tìm.
Các cờ dùng để làm gì?
Toàn cục (g) tìm tất cả các kết quả khớp. Không phân biệt hoa thường (i) bỏ qua chữ hoa/chữ thường. Đa dòng (m) làm cho ^ và $ khớp với ranh giới dòng thay vì ranh giới chuỗi.
Tôi có thể sử dụng cheatsheet này trong mã của mình không?
Có! Khi bạn đã kiểm tra một mẫu và xác nhận nó hoạt động, sao chép mẫu regex trực tiếp vào mã JavaScript, Python hoặc bất kỳ ngôn ngữ nào khác.
Lịch sử ngắn gọn của ngôn ngữ mẫu
Biểu thức chính quy ra đời như một mảnh của khoa học máy tính lý thuyết. Stephen Kleene định nghĩa "tập chính quy" trong bài báo năm 1956 về mạng nơ-ron; Ken Thompson đưa chúng vào Unix năm 1968 với grep. Thư viện regex mã nguồn mở của Henry Spencer (giữa thập niên 1980) trở thành nền tảng cho nhiều cài đặt sau này. Larry Wall mở rộng đáng kể cú pháp trong Perl, và "Perl-compatible regular expressions" (PCRE) của ông trở thành chuẩn thực tế mà phần lớn các ngôn ngữ hiện đại theo. Ngày nay có nhiều biến thể regex gần gũi nhưng vẫn khác biệt tinh tế, và một mẫu chạy được ở engine này không phải lúc nào cũng chạy giống hệt ở engine khác.
Engine nơi mẫu của bạn vận hành
Cùng một cú pháp có thể mang ý nghĩa khác nhau ở các engine khác nhau. Các họ lớn:
- POSIX BRE (Basic Regular Expressions), được dùng trong chế độ mặc định của
grepvàsed. Nhiều siêu ký tự đòi hỏi escape bằng backslash:(,),{,},+,?,|được coi là nguyên văn nếu không escape. - POSIX ERE (Extended Regular Expressions), được dùng bởi
egrepvàawk. Các siêu ký tự trên hoạt động mà không cần escape. - PCRE (Perl-Compatible Regular Expressions), mở rộng ERE với lookaround, nhóm nguyên tử, bắt có tên và tham chiếu ngược. Được PHP và phần lớn các ngôn ngữ hiện đại sử dụng. Các viết tắt lớp gốc Perl
\d,\w,\sphổ biến trong PCRE, JavaScript, .NET, Java và Python. - JavaScript RegExp, gần với PCRE nhưng có những khác biệt đáng kể. ES2018 bổ sung lookbehind, nhóm bắt có tên, cờ dotall
svà escape thuộc tính Unicode thông qua cờu. Cờvcho ký pháp tập hợp xuất hiện trong ES2024. - Python
revà Pythonregex,renằm trong thư viện chuẩn; mô-đun bên thứ baregexthêm các tính năng nhận biết Unicode, lookbehind độ rộng biến đổi và các nâng cấp kiểu PCRE khác. - RE2 (thư viện của Google, dùng trong Go), bảo đảm thời gian tuyến tính nhưng không hỗ trợ tham chiếu ngược hay lookaround. Đánh đổi: hiệu năng có thể dự đoán, ít tính năng hơn.
Bộ thử nghiệm tương tác của cheatsheet này chạy bằng JavaScript, nên mẫu được đánh giá bởi engine JS của trình duyệt. Mẫu chạy được ở đây có thể hoạt động khác trong Python hay PHP. Phần lớn khác biệt nằm ở các tính năng nâng cao (lookbehind, escape thuộc tính Unicode, tham chiếu ngược) chứ không phải cú pháp cơ bản.
Các khối xây dựng cốt lõi
Hầu hết mọi mẫu regex đều được dựng từ các thành phần sau:
- Ký tự nguyên văn, khớp với chính nó.
catkhớp với chuỗi con "cat". - Mỏ neo,
^(đầu chuỗi hoặc đầu dòng),$(cuối),\b(ranh giới từ),\B(không phải ranh giới từ). - Lớp ký tự,
[abc]khớp với a, b hoặc c.[^abc]phủ định.[a-z]là khoảng. Viết tắt:\d(chữ số),\w(ký tự từ: chữ, số, gạch dưới),\s(khoảng trắng), và bản in hoa để phủ định (\D,\W,\S). - Bộ lượng hóa,
?(0 hoặc 1),*(0 trở lên),+(1 trở lên),{n},{n,},{n,m}. Mặc định là tham lam (khớp càng nhiều càng tốt); thêm?để chuyển sang lười:*?,+?,??. - Nhóm,
(...)có bắt,(?:...)không bắt,(?<name>...)có tên (PCRE, JS, Python). - Lựa chọn thay thế,
cat|dogkhớp với một trong hai. - Lookaround,
(?=...)lookahead dương,(?!...)lookahead âm,(?<=...)lookbehind dương,(?<!...)lookbehind âm. Khớp mà không tiêu thụ ký tự. - Tham chiếu ngược,
\1,\2(theo số),\k<name>(theo tên). Khớp với cùng văn bản mà nhóm bắt tương ứng đã khớp. - Cờ,
g(toàn cục),i(không phân biệt hoa thường),m(đa dòng:^và$khớp ranh giới dòng),s(dotall:.khớp cả newline),u(Unicode),y(sticky trong JS).
Những mẫu đáng thuộc
Có vài mẫu xuất hiện thường xuyên đến mức đáng giữ trong đầu:
| Mục đích | Mẫu |
|---|---|
| Email (cơ bản) | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ |
| URL | https?://[^\s]+ |
| Số điện thoại Mỹ | \(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4} |
| Ngày ISO (YYYY-MM-DD) | \d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) |
| Địa chỉ IPv4 (không kiểm tra octet) | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b |
| Màu hex | ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ |
| Khoảng trắng ở đầu hoặc cuối dòng | ^\s+|\s+$ |
| Nhiều khoảng trắng liên tiếp | \s{2,} |
Một ghi chú về regex email: kiểm tra email đầy đủ theo RFC 5322 cần một regex quái dị 6.000 ký tự. Mẫu đơn giản phía trên chấp nhận 99% địa chỉ email thực và không loại bỏ bất kỳ địa chỉ hợp lệ nào; với môi trường thực tế, hãy gửi email xác nhận thay vì cố kiểm tra cú pháp hoàn hảo.
Tham lam và lười: bất ngờ thường gặp
Mặc định, các bộ lượng hóa tham lam: chúng khớp càng nhiều càng tốt miễn là mẫu tổng thể vẫn khớp được. Vì vậy <.+> áp lên <a>text</a> khớp với toàn bộ chuỗi, không chỉ <a>, vì .+ ngấu nghiến càng nhiều càng tốt. Để khớp với chuỗi nhỏ nhất có thể, hãy thêm ? vào sau bộ lượng hóa: <.+?> khớp <a> rồi đến </a> riêng rẽ. Lựa chọn tham lam/lười là một trong những nguyên nhân phổ biến nhất gây ra lỗi kiểu "tại sao regex của tôi không khớp đúng như mong đợi".
Backtracking thảm họa và ReDoS
Một số mẫu regex có thể mất thời gian theo cấp số nhân để thất bại trên những đầu vào nhất định, đây là lớp lỗ hổng từ chối dịch vụ gọi là ReDoS (Regular Expression Denial of Service). Thủ phạm kinh điển là các bộ lượng hóa lồng nhau như (a+)+ hoặc (a|aa)+ áp lên một chuỗi dài các ký tự a đi kèm một ký tự không khớp ở cuối. Engine thử mọi cách có thể để chia chuỗi trước khi từ bỏ, và số cách đó tăng theo cấp số nhân.
Sự cố thực tế: gián đoạn Cloudflare năm 2019 do một regex triển khai trong luật WAF bị backtracking thảm họa trên các đầu vào nhất định. Stack Overflow gặp sự cố tương tự vào tháng 7 năm 2016: một regex trim (^[\s]+|[\s]+$) rơi vào backtracking theo cấp số nhân với một bình luận đơn lẻ chứa khoảng 20.000 ký tự khoảng trắng liên tiếp, khiến trang sập 34 phút. Thói quen phòng thủ: tránh bộ lượng hóa lồng nhau, ưu tiên nhóm nguyên tử ((?>...)) nếu được hỗ trợ, và cân nhắc dùng RE2 hoặc engine tuyến tính cho đầu vào không tin cậy.
Đặc thù từng ngôn ngữ đáng biết
- JavaScript: backslash cần escape gấp đôi trong literal chuỗi (
"\\d") nhưng không cần trong literal regex (/\d/). Khi có thể, hãy dùng dạng literal regex. - Python: hãy dùng raw string (
r"\d+") để tránh phiền phức với backslash. Mô-đunrenằm trong thư viện chuẩn;regextrên PyPI bổ sung các tính năng phụ. - Java: backslash cần escape bốn lần (
"\\\\d"cho\d) vì literal chuỗi Java dùng\làm ký tự escape, sau đó trình biên dịch regex thấy\\d. - Bash: khớp regex trong
[[ string =~ pattern ]]dùng POSIX ERE. Quy tắc quoting rắc rối; hãy đọcman bash. - Go: dùng RE2, nên tham chiếu ngược và lookaround không có sẵn. Đánh đổi: bảo đảm thời gian tuyến tính.
Khi nào KHÔNG nên dùng regex
Câu nổi tiếng năm 1997 của Jamie Zawinski: "Một số người, khi gặp vấn đề, nghĩ 'tôi biết rồi, tôi sẽ dùng biểu thức chính quy.' Giờ họ có hai vấn đề."
- Đừng phân tích HTML hoặc XML bằng regex. Hãy dùng parser thực thụ (DOMParser trong trình duyệt, BeautifulSoup trong Python, jsoup trong Java, v.v.). Cấu trúc lồng nhau của HTML về cơ bản nằm ngoài khả năng diễn đạt sạch sẽ của regex.
- Đừng phân tích JSON bằng regex. Hãy dùng JSON.parse hoặc parser JSON của thư viện chuẩn.
- Đừng kiểm tra email nghiêm ngặt bằng regex. Hãy gửi email xác nhận; đó là phép kiểm tra đáng tin cậy duy nhất.
- Đừng viết parser CSV bằng regex. Trường có dấu nháy chứa dấu phẩy, dấu nháy được escape và giá trị nhiều dòng nhanh chóng vượt quá những gì regex xử lý gọn được.
- Đừng cố khớp các dấu ngoặc cân bằng. Regex chuẩn không thể (đó là ngôn ngữ phi ngữ cảnh); một số engine PCRE có tính năng đệ quy "gian lận", nhưng parser thực thụ vẫn gọn gàng hơn.
Sai lầm phổ biến
- Quên escape các ký tự đặc biệt.
.,*,?,+,(,),[,],{,},\,^,$,|,/đều có nghĩa đặc biệt. Để khớp chúng nguyên văn, hãy đặt backslash phía trước. - Bộ lượng hóa tham lam ngốn quá nhiều. Thêm
?cho khớp lười khi bạn muốn kết quả nhỏ nhất. - Quên cờ global và không hiểu vì sao chỉ thấy khớp đầu tiên.
String.prototype.match()của JavaScript chỉ trả về khớp đầu tiên nếu thiếu cờg. - Backtracking thảm họa trên đầu vào dài. Các bộ lượng hóa lồng nhau như
(a+)+có thể treo trên đầu vào nhất định. Hãy thử với các trường hợp biên. - Mặc định cùng một regex hoạt động giống nhau trong mọi ngôn ngữ. Lookbehind, escape Unicode và các viết tắt lớp ký tự đều khác nhau.
- Cố kiểm tra email quá nghiêm. Regex đúng kỹ thuật theo RFC 5322 thì không thể bảo trì; regex đơn giản kèm email xác nhận khi đăng ký mới là mẫu thực dụng.
- Dùng regex cho HTML, JSON hoặc CSV. Hãy dùng parser chuyên dụng; thời gian tiết kiệm ban đầu sẽ mất ngược cho lỗi.
Các câu hỏi thường gặp khác
Vì sao mẫu của tôi chạy được ở đây mà thất bại trong mã của tôi?
Nguyên nhân phổ biến nhất là khác biệt engine. RegExp của JavaScript không hỗ trợ một số tính năng có ở PCRE (và ngược lại). Các bẫy thường gặp: lookbehind được thêm muộn vào JS (ES2018), cú pháp nhóm có tên hơi khác, escape thuộc tính Unicode cần cờ u, và các lớp ký tự POSIX như [[:alpha:]] hầu như không có trong JS. Hãy thử ngay trên engine bạn sẽ triển khai.
Có cách "toàn cục" nào để khớp xuyên nhiều dòng không?
Hai cờ làm việc cùng nhau. Cờ m (đa dòng) khiến ^ và $ khớp đầu và cuối từng dòng thay vì toàn chuỗi. Cờ s (dotall) khiến . cũng khớp ký tự newline. Kết hợp với g để toàn cục, bạn có thể viết các mẫu trải nhiều dòng và tìm mọi khớp: /^foo.+$/gms.
Mẫu và văn bản thử của tôi có được gửi đi đâu không?
Không. Việc khớp mẫu dùng engine JavaScript RegExp tích hợp sẵn của trình duyệt; không có gì được tải lên bất kỳ máy chủ nào. Điều này quan trọng khi bạn thử mẫu trên log sản xuất thực, phản hồi API nội bộ hoặc nội dung nhạy cảm.
Tôi có nên học lookbehind không?
Hữu ích nhưng không bắt buộc. Lookbehind cho phép bạn khớp văn bản đứng sau một thứ gì đó mà không gộp "thứ đó" vào kết quả khớp. Ví dụ: (?<=\$)\d+ khớp các chữ số sau dấu đô la mà không tiêu thụ dấu đô la. Được hỗ trợ trong PCRE, JavaScript hiện đại (ES2018+) và mô-đun regex của Python. Nếu viết mẫu mang tính di động, hãy kiểm tra engine đích trước.
Vì sao dùng (?:...) thay vì (...)?
Nhóm không bắt ((?:...)) nhanh hơn một chút, không chiếm slot trong mảng bắt và giữ kết quả khớp sạch sẽ. Hãy dùng bất cứ khi nào bạn cần gom nhóm để chọn lựa hay lượng hóa nhưng không cần trích văn bản khớp. (http|https):// tạo ra một bắt mà bạn có thể không cần; (?:http|https):// thì không.
Cách đúng để khớp ký tự Unicode là gì?
Trong JavaScript, thêm cờ u và dùng escape thuộc tính Unicode: /\p{Letter}+/gu khớp các chuỗi chữ ở mọi hệ chữ. Không có cờ u, \w chỉ khớp ký tự từ ASCII. Mô-đun re của Python nhận biết Unicode mặc định trong Python 3. Java cần Pattern.UNICODE_CHARACTER_CLASS. Hầu hết các engine đều có cách bật Unicode; hãy xem tài liệu của engine bạn dùng.