Giải thích regex: dán một pattern có sẵn để biết từng ký hiệu trong đó nghĩa là gì
Dán một regular expression đã viết sẵn vào ô pattern, công cụ quét qua chuỗi đó và liệt kê ra những ký hiệu regex mà nó nhận ra, mỗi ký hiệu kèm một câu giải nghĩa bằng tiếng Việt. Kèm theo là ba cảnh báo về các kiểu viết dễ gây match quá rộng hoặc chạy chậm, và một ô test string để bạn xem ngay pattern đó bắt được những đoạn nào.
Tính năng nổi bật
- Nhận diện hai mươi sáu ký hiệu regex hay gặp và giải nghĩa từng ký hiệu bằng tiếng Việt
- Phân biệt được ký hiệu thật với ký hiệu đã bị vô hiệu bằng dấu gạch chéo ngược, nên \. không bị đọc nhầm thành dấu chấm ký hiệu
- Đọc riêng ô flags và nhắc lại tác động của flags lên cách pattern chạy
- Ba cảnh báo tự động: dùng .* dễ nuốt quá rộng, dấu hiệu quantifier lồng nhau, và thiếu flag g khi cần lấy nhiều kết quả
- Ô test string chạy thử ngay, hiện số lượng đoạn khớp cùng vị trí index của từng đoạn
- Nút sao chép xuất pattern kèm flags theo dạng literal của JavaScript để dán thẳng vào mã nguồn
- Không dựng cây cú pháp và không gọi mô hình ngôn ngữ, nên kết quả cố định và không bao giờ bịa ý nghĩa cho ký hiệu lạ
- Chạy hoàn toàn trong trình duyệt, pattern và test string không được gửi lên máy chủ nào
Regex khó đọc vì nó nén quá nhiều quy tắc vào quá ít ký tự
Một dòng regex ba chục ký tự có thể chứa từng đó quyết định thiết kế, mà không có khoảng trắng nào phân tách và không có tên biến nào gợi ý. Điều đó khiến việc đọc regex của người khác khác hẳn việc đọc mã nguồn của người khác: bạn không lướt được, phải soi từng ký tự một và tự nhớ mỗi ký tự nghĩa là gì trong ngữ cảnh nó đứng. Tình huống thường gặp nhất là bạn nhận một pattern từ mã nguồn cũ, từ một câu trả lời trên diễn đàn hoặc từ một trợ lý viết mã, nó có vẻ chạy đúng trên vài ví dụ, và bạn phải quyết định có đưa vào sản phẩm hay không. Rủi ro ở đây không đối xứng: một regex kiểm tra dữ liệu đầu vào quá lỏng sẽ cho lọt dữ liệu rác, một regex quá chặt sẽ chặn nhầm người dùng hợp lệ, còn một regex viết ẩu có thể làm treo tiến trình khi gặp chuỗi dài. Trang này giải quyết bước đầu tiên trong chuỗi đó, tức là bước đọc hiểu. Nó không viết regex thay bạn và không thay thế việc chạy thử kỹ càng, nhưng nó rút ngắn đáng kể khoảng thời gian bạn ngồi nhìn một dòng ký hiệu mà không biết bắt đầu từ đâu.
Lợi ích khi sử dụng
- Đọc được pattern của người khác mà không cần mở tài liệu tra cứu song song
- Bắt sớm hai lỗi kinh điển là nuốt quá rộng và quantifier lồng nhau, trước khi chúng lên môi trường thật
- Thấy ngay vị trí index của từng đoạn khớp, tiện khi cần cắt chuỗi theo kết quả
- Học regex theo lối đọc ngược từ pattern thật thay vì học thuộc bảng ký hiệu khô khan
- Pattern nội bộ chứa tên miền hay định dạng mã khách hàng không phải rời khỏi máy của bạn
Cách đọc một pattern lạ trong vài phút
- 1Dán pattern vào ô đầu tiên, chỉ phần thân chứ không cần hai dấu gạch chéo bao ngoài.
- 2Điền các chữ cái flags vào ô thứ hai đúng như trong mã nguồn gốc, vì flags đổi hẳn cách pattern chạy.
- 3Đọc dòng tóm tắt để biết công cụ nhận ra bao nhiêu cấu trúc, rồi đọc lần lượt từng ký hiệu kèm giải nghĩa bên dưới.
- 4Xem phần cảnh báo nếu có, đây là chỗ hay chỉ ra vấn đề mà mắt thường bỏ qua.
- 5Dán vào ô test string vài đoạn văn bản thật, gồm cả trường hợp hợp lệ lẫn trường hợp cần bị loại, rồi đối chiếu danh sách đoạn khớp cùng vị trí index với điều bạn mong đợi.
Công cụ quét theo bảng ký hiệu chứ không dựng cây cú pháp, và điều đó thay đổi cách bạn đọc kết quả
Cơ chế bên trong rất đáng biết vì nó quyết định kết quả nào đáng tin và kết quả nào cần bạn tự kiểm lại. Công cụ giữ một bảng gồm hai mươi sáu mục, mỗi mục là một ký hiệu regex kèm sẵn một câu giải nghĩa viết tay. Với mỗi mục, nó kiểm tra xem ký hiệu đó có xuất hiện trong pattern của bạn ở dạng chưa bị vô hiệu hóa hay không, tức là phía trước không có dấu gạch chéo ngược. Ký hiệu nào xuất hiện thì câu giải nghĩa của nó được đưa vào danh sách kết quả. Điểm mạnh của cách làm này là nó không bao giờ bịa: mọi câu chữ bạn đọc được đều do người viết công cụ soạn sẵn cho đúng ký hiệu đó, không có bước sinh văn bản tự do. Trước khi dò, công cụ thay nội dung bên trong mỗi lớp ký tự vuông bằng một chỗ trống, vì ở đó dấu chấm và dấu cộng chỉ là chữ thường chứ không mang nghĩa ký hiệu. Nhờ vậy pattern mẫu có sẵn trên trang không còn bị liệt kê nhầm dấu chấm nằm trong ngoặc vuông. Nó cũng đếm số gạch chéo ngược đứng trước để phân biệt \d là lớp chữ số với \\d là gạch chéo rồi chữ d. Điểm yếu còn lại có hai. Thứ nhất, kết quả là một danh sách chứ không phải một bản phân tích theo thứ tự, nên nó cho bạn biết trong pattern có những gì chứ không cho biết ký hiệu nào đứng ở đâu và bao trùm phạm vi nào. Thứ hai, nó chỉ báo có hay không chứ không đếm số lần xuất hiện. Vì vậy hãy dùng danh sách này như một bản kiểm kê để định hướng, còn phạm vi tác dụng của từng ký hiệu thì vẫn phải tự đọc trên chính pattern.
Mười sáu ký hiệu trong bảng và những ký hiệu bạn phải tự tra
Bảng gồm hai neo là ^ đánh dấu đầu chuỗi và $ đánh dấu cuối chuỗi, cả hai chuyển sang nghĩa đầu dòng và cuối dòng khi bật flag m. Có dấu chấm nghĩa là một ký tự bất kỳ trừ ký tự xuống dòng, trừ khi bật flag s. Có ba lớp ký tự viết tắt là \d cho chữ số, \w cho chữ cái số và gạch dưới, \s cho khoảng trắng các loại. Có bốn bộ đếm lặp là * cho không hoặc nhiều lần, + cho một hoặc nhiều lần, ? cho có hoặc không đồng thời mang vai trò chuyển bộ đếm sang chế độ lười, và {n,m} cho khoảng lặp cụ thể. Có hai dạng lớp ký tự tự định nghĩa là [abc] cho tập cho phép và [^abc] cho tập loại trừ. Có hai dạng nhóm là ngoặc tròn thường để bắt giữ giá trị và ngoặc tròn kèm ?: để gom nhóm mà không bắt giữ. Có bốn dạng nhìn quanh gồm ?= và ?<= khẳng định, ?! và ?<! phủ định. Bảng còn có dấu gạch đứng chỉ phép hoặc, \b và \B cho biên từ, ba lớp phủ định \D \W \S, nhóm đặt tên dạng ?<ten>, và tham chiếu ngược dạng \1. Nhờ vậy pattern mẫu mặc định trên trang, vốn mở đầu bằng \b, được giải thích đầy đủ. Những ký hiệu hiếm hơn như nhóm nguyên tử hay thuộc tính Unicode \p thì vẫn nằm ngoài bảng, gặp thì tra ở trang /vi/tools/regex-cheatsheet.
Ba cảnh báo tự động và lý do chúng đáng được xem trọng
Cảnh báo thứ nhất bật lên khi pattern chứa dấu chấm đi kèm dấu sao. Cặp này khớp mọi thứ dài bao nhiêu cũng được, và vì bộ đếm mặc định chạy ở chế độ tham lam nên nó luôn nuốt tới cuối chuỗi rồi mới lùi dần lại để tìm phần còn lại của pattern. Hậu quả điển hình là khi bóc nội dung giữa hai dấu mốc, bạn nhận về một đoạn kéo từ dấu mốc đầu tiên tới dấu mốc cuối cùng trong cả chuỗi thay vì cặp gần nhau nhất. Cách chữa là thêm dấu hỏi để chuyển sang chế độ lười, hoặc thay hẳn bằng lớp phủ định loại trừ chính ký tự đóng. Cảnh báo thứ hai bật lên khi công cụ thấy dấu hiệu một bộ đếm nằm trong một nhóm mà bên ngoài nhóm lại có thêm bộ đếm nữa. Cấu trúc này mở đường cho hiện tượng quay lui thảm họa: khi gặp một chuỗi dài mà không khớp được ở cuối, số cách chia chuỗi mà bộ máy phải thử tăng theo cấp số nhân, và một chuỗi vài chục ký tự đủ sức làm treo tiến trình. Đây chính là nền của lỗ hổng từ chối dịch vụ qua regex, đáng ngại nhất khi pattern được đem đi kiểm tra dữ liệu do người dùng nhập vào. Cảnh báo thứ ba nhắc khi ô flags chưa có chữ g. Không có nó, hàm khớp trong JavaScript chỉ trả về kết quả đầu tiên kèm các nhóm bắt giữ, thay vì trả về mảng tất cả kết quả. Riêng ô test string trên trang này luôn tự thêm chữ g khi chạy thử để đếm được đủ số đoạn khớp, nên đừng lấy con số đó làm bằng chứng rằng mã nguồn của bạn cũng sẽ lấy được đủ.
Flags quyết định pattern chạy thế nào, nên đừng bỏ trống ô đó
Cùng một pattern nhưng đổi flags là đổi hẳn hành vi, vì vậy khi chép regex từ mã nguồn ra hãy chép luôn phần chữ cái đứng sau dấu gạch chéo cuối. Chữ g bật chế độ tìm toàn cục, cho phép lấy về mọi đoạn khớp thay vì dừng ở đoạn đầu tiên. Chữ i bỏ qua phân biệt chữ hoa chữ thường, rất hay dùng với địa chỉ thư điện tử và tên miền. Chữ m đổi nghĩa của hai neo đầu và cuối từ phạm vi cả chuỗi sang phạm vi từng dòng, đây là chữ hay bị quên khi xử lý nhật ký nhiều dòng. Chữ s cho dấu chấm khớp được cả ký tự xuống dòng, cần thiết khi bóc một khối văn bản trải qua nhiều dòng. Chữ u bật chế độ hiểu đúng ký tự nhiều byte và mở khóa cú pháp thuộc tính Unicode, có ý nghĩa lớn với tiếng Việt vì chữ có dấu nằm ngoài bảng chữ cái cơ bản; đáng chú ý là \w vẫn chỉ hiểu chữ cái không dấu ngay cả khi đã bật chữ u, nên muốn khớp chữ tiếng Việt phải liệt kê khoảng ký tự hoặc dùng thuộc tính Unicode. Chữ y bật chế độ dính, buộc phép khớp phải bắt đầu đúng tại vị trí con trỏ hiện tại. Chữ d yêu cầu trả về thêm chỉ số đầu và cuối của từng nhóm bắt giữ. Một cái bẫy đi kèm chữ g cần nhớ khi đọc mã nguồn: đối tượng regex có chữ g sẽ nhớ vị trí lần khớp trước, nên gọi hàm kiểm tra hai lần liên tiếp trên cùng một chuỗi có thể cho hai kết quả khác nhau.
Trang này đứng ở đâu trong nhóm công cụ regex của site
Nhóm regex trên site được chia theo việc bạn đang cần làm chứ không theo mức độ nâng cao, nên chọn đúng trang sẽ nhanh hơn nhiều. Trang bạn đang xem dành cho tình huống bạn đã có sẵn một pattern và cần hiểu nó, đầu vào là chuỗi regex và đầu ra là danh sách ký hiệu kèm giải nghĩa. Nếu bạn chưa có pattern nào mà chỉ có mô tả bằng lời, hãy bắt đầu ở /vi/tools/regex-generator, nơi sinh ra pattern từ yêu cầu của bạn. Khi đã có pattern và muốn thử nó trên nhiều mẫu văn bản để xem khớp ở đâu, dùng /vi/tools/regex-tester. Khi pattern chạy sai và bạn cần dò từng bước xem nó gãy ở chỗ nào cùng với giá trị của từng nhóm bắt giữ, dùng /vi/tools/regex-debugger. Khi bạn muốn nhìn cấu trúc pattern dưới dạng sơ đồ đường đi thay vì dưới dạng danh sách chữ, dùng /vi/tools/regex-visualizer. Khi việc cần làm không phải là tìm mà là thay thế hàng loạt, kể cả có tham chiếu tới nhóm bắt giữ trong chuỗi thay thế, dùng /vi/tools/regex-replace. Khi bạn cần tra nhanh một ký hiệu hiếm nằm ngoài bảng của trang này, mở /vi/tools/regex-cheatsheet. Còn khi bạn không muốn tự viết mà chỉ cần lấy một pattern đã kiểm chứng cho các việc quen thuộc như số điện thoại hay mã số thuế, xem /vi/tools/regex-collection. Trình tự phối hợp thường dùng là sinh hoặc lấy pattern, đọc hiểu ở trang này, rồi thử kỹ ở trang tester trước khi đưa vào mã nguồn.
Câu hỏi thường gặp (FAQ)
Công cụ nhận diện được bao nhiêu ký hiệu regex?
Hai mươi sáu ký hiệu hay gặp nhất, gồm hai neo đầu cuối, dấu chấm, dấu gạch đứng, hai dạng biên từ, sáu lớp viết tắt cả khẳng định lẫn phủ định, bốn bộ đếm lặp, hai dạng lớp ký tự vuông, ba dạng nhóm, bốn dạng nhìn quanh và tham chiếu ngược. Ký hiệu hiếm nằm ngoài danh sách này sẽ không xuất hiện trong phần giải thích, và công cụ cũng không báo là nó bỏ qua.
Vì sao dấu chấm nằm trong ngoặc vuông vẫn được giải thích là ký tự bất kỳ?
Vì phép kiểm tra chỉ nhìn xem ký hiệu có mặt trong chuỗi hay không, không xét ngữ cảnh xung quanh. Bên trong lớp ký tự vuông, dấu chấm và dấu cộng chỉ mang nghĩa chữ cái thường, nhưng công cụ vẫn liệt kê chúng. Đây là điểm cần bạn tự kiểm lại trên chính pattern, nhất là với pattern có nhiều lớp ký tự.
Ký hiệu \b đánh dấu biên từ có được giải thích không?
Có. Ký hiệu này khớp với ranh giới giữa một ký tự thuộc nhóm chữ cái số gạch dưới và một ký tự không thuộc nhóm đó, dùng để buộc pattern khớp trọn một từ thay vì khớp một mảnh nằm giữa từ dài hơn. Một lưu ý quan trọng với tiếng Việt: \b chỉ hiểu ký tự ASCII, nên nó không nhận ra ranh giới ở các chữ có dấu. Muốn khớp trọn từ tiếng Việt thì phải tự viết lớp ký tự bao gồm dải À-ỹ thay vì dựa vào \b.
Ô test string hiện không có đoạn nào khớp dù tôi tin pattern viết đúng, vì sao?
Nhiều khả năng pattern hoặc chuỗi flags đang sai cú pháp. Khi việc dựng đối tượng regex thất bại, công cụ nuốt lỗi và trả về danh sách rỗng, tức là bạn thấy con số không chứ không thấy thông báo lỗi. Hãy soát lại dấu ngoặc có đóng đủ chưa và ô flags có chứa chữ cái lạ không, sau đó thử lại.
Cảnh báo chưa bật flag g có bắt buộc phải xử lý không?
Không, nó chỉ nhắc chứ không phải lỗi. Nếu bạn chỉ cần kiểm tra một chuỗi có hợp lệ hay không thì không cần chữ g. Nhưng lưu ý ô test string trên trang này luôn tự thêm chữ g khi chạy thử để đếm đủ số đoạn khớp, nên số lượng bạn thấy ở đây có thể nhiều hơn số kết quả mà mã nguồn của bạn thực sự nhận về.
Cảnh báo về dấu chấm đi kèm dấu sao nghĩa là gì?
Cặp đó khớp mọi thứ với độ dài tùy ý và chạy ở chế độ tham lam, nghĩa là nó nuốt tới cuối chuỗi rồi mới lùi lại. Khi bóc nội dung giữa hai dấu mốc, bạn thường nhận về một đoạn kéo từ mốc đầu tiên tới mốc cuối cùng thay vì cặp gần nhau nhất. Cách chữa là thêm dấu hỏi để chuyển sang chế độ lười hoặc dùng lớp phủ định loại trừ ký tự đóng.
Quantifier lồng nhau nguy hiểm ở chỗ nào?
Khi một bộ đếm nằm trong nhóm mà ngoài nhóm lại có bộ đếm nữa, số cách chia chuỗi mà bộ máy phải thử có thể tăng theo cấp số nhân trong trường hợp không khớp được. Một chuỗi vài chục ký tự đủ để làm treo tiến trình, và đây chính là nền của lỗ hổng từ chối dịch vụ qua regex khi pattern được dùng để kiểm tra dữ liệu người dùng nhập.
Công cụ có phân biệt được dấu chấm đã bị vô hiệu hóa với dấu chấm mang nghĩa ký hiệu không?
Có. Phép kiểm tra dùng điều kiện nhìn ngược để loại trừ trường hợp ngay trước ký hiệu là một dấu gạch chéo ngược. Nhờ vậy một pattern chỉ chứa dấu chấm đã vô hiệu hóa sẽ không bị báo là có ký hiệu khớp mọi ký tự, tránh được kiểu hiểu nhầm hay gặp khi đọc pattern kiểm tra tên miền.
Lookbehind có chạy được trên mọi trình duyệt không?
Ngày nay thì hầu như có, nhưng đây từng là điểm khác biệt lớn giữa các trình duyệt và vẫn đáng nhớ khi bạn bảo trì mã cũ hoặc nhắm tới thiết bị đời cũ. Nếu môi trường đích không hỗ trợ, cách thay thế thường dùng là bắt giữ phần đứng trước bằng một nhóm rồi bỏ nó đi khi xử lý kết quả.
Trang này khác Regex Tester, Regex Debugger và Regex Visualizer thế nào?
Khác ở đầu ra. Trang này trả về danh sách ký hiệu kèm giải nghĩa bằng chữ. Trang tại /vi/tools/regex-tester cho bạn thử pattern trên nhiều mẫu văn bản và xem chỗ nào khớp. Trang tại /vi/tools/regex-debugger đi sâu vào từng bước khớp cùng giá trị các nhóm. Trang tại /vi/tools/regex-visualizer vẽ cấu trúc pattern thành sơ đồ đường đi.
Tôi chưa có regex nào, chỉ có mô tả bằng lời thì nên dùng gì?
Hãy bắt đầu ở /vi/tools/regex-generator để sinh pattern từ yêu cầu, hoặc lấy một pattern đã kiểm chứng sẵn tại /vi/tools/regex-collection nếu việc của bạn thuộc loại quen thuộc như số điện thoại hay địa chỉ thư điện tử. Có pattern rồi thì quay lại trang này để đọc hiểu trước khi đưa vào mã nguồn.
Regex viết cho PHP hoặc Python dán vào đây có được giải thích đúng không?
Phần lớn các ký hiệu trong bảng mang cùng ý nghĩa ở mọi bộ máy nên phần giải nghĩa vẫn đúng. Nhưng ô test string chạy bằng bộ máy regex của JavaScript, nên các cú pháp riêng của bộ máy khác như neo đầu chuỗi tuyệt đối, chú thích trong pattern hay chế độ viết thoáng nhiều dòng sẽ không cho kết quả như bên ngôn ngữ gốc.
Từ khóa liên quan
- giải thích regex
- regex explain online
- đọc hiểu regular expression
- regex tiếng Việt là gì
- ý nghĩa ký hiệu regex
- regex lookahead lookbehind
- capture group là gì
- non capturing group
- quantifier tham lam và lười
- regex flags g i m s u y
- catastrophic backtracking regex
- redos lỗ hổng regex
- regex khớp email
- regex trong javascript
- phân biệt \d \w \s
- lớp ký tự trong regex
- regex khớp tiếng Việt có dấu
- công cụ phân tích regex online
- học regex cho người mới
- kiểm tra regex trước khi dùng