Regular Expression (thường viết tắt là Regex hoặc Regexp): là các ký hiệu (theo quy ước) dùng để mô tả thay cho các chuỗi (string) khác. Regex thường được dùng để tìm kiếm và thay thế trong xử lý chuỗi. Tôi tạm dịch là biểu thức mô tả, một số tài liệu dịch là biểu thức chính quy.


Chủ đề này rất hại não, chỉ dùng cho các bạn yêu thích lập trình thôi nhé. Theo tôi, Regex sẽ là cái bạn ghét nhất khi đọc code của người khác. Trong bài này, tôi cố gắng làm rõ vấn đề này để các bạn không còn sợ hãi khi gặp phải, hiểu Regular Expression sẽ giúp bạn tìm kiếm và xử lý chuỗi nhanh nhất.
 
Regex thường được viết giữa hai dấu /    /

  • Ví dụ: /TapHuan/ có nghĩa là tìm chuỗi taphuan 

Người ta có thể thêm một số ký tự đằng sau để quy định cách thức tìm kiếm

  • /TapHuan/g: g là global, yêu cầu tìm trên cả văn bản
  • /TapHuan/i: i là Case-insensitive, tìm không phân biệt chữ hoa, chữ thường
  • /TapHuan/m: m là multiline, tìm trên nhiều dòng

Phần lý thuyết này dùng để tra cứu lại sau khi bạn hiểu về Regex. Bạn nào biết sơ sơ Regex thì bỏ qua phần này, xuống thẳng phần ví dụ để ôn tập. Bạn nào mới tìm hiểu thì đọc qua 1 lần, chổ nào không hiểu thì cứ bỏ qua. Regex quy ước như sau:
Ký tự đại diện
  • [ABC] tìm tất cả ký tự nằm trong ngoặt vuông
  • [^ABC] tìm tất cả ký tự không nằm trong ngoặt vuông
  • [0-9] tìm tất cả các chữ số từ 0 đến 9
  • [A-Z] tìm tất cả các ký tự nằm trong khoảng từ A hoa đến Z hoa
  • [a-z] tìm tất cả các ký tự nằm trong khoảng từ a thường đến z thường
  • [A-z] tìm tất cả các ký tự nằm trong khoảng từ A hoa đến z thường
  • . dấu chấm đại diện cho bất kỳ ký tự nào ngoại từ ký tự xuống dòng & kết thúc dòng
  • \w đại diện cho một từ, tương đương với [A-Za-z0-9_]
  • \W ngược lại với \w, đại diện cho chuỗi không phải từ, tương đương với [^A-Za-z0-9_], ví dụ dấu phẩy, khoảng trắng...
  • \d đại diện cho ký tự số, tương đương với [0-9]
  • \D ngược lại với \d, đại diện cho ký tự không phải số, tương đương với [^0-9]
  • \s đại diện cho ký tự khoảng trắng
  • \S đại diện cho ký tự không phải khoảng trắng
  • \xxx : tìm một ký tự Latin được chỉ định bởi số xxx dạng bát phân (octal)
  • \xdd : tìm một ký tự được chỉ định bởi 1 số dạng hexa
  • \uxxxx : tìm một ký tự Unicode được chỉ định bởi số xxxx dạng hexa
Nhóm các ký tự
  • (abc) tìm nhóm ký tự abc và lưu lại kết quả tìm để tham tham chiếu lại nếu cần
  • \1 trả về chuỗi phù hợp thứ nhất ở kết quả tìm nhóm ký tự trước đó
  • (?:abc) tìm nhóm ký tự abc và không lưu kết quả tìm
  • (?=abc) thường có thêm biểu thức chính phía trước, tìm nhóm ký tự phù hợp biểu thức chính và có nhóm ký tự abc theo sau. Chuỗi trả về không bao gồm nhóm ký tự abc.
  • (?!abc) thường có thêm biểu thức chính phía trước, tìm nhóm ký tự phù hợp biểu thức chính và không có nhóm ký tự abc theo sau. Chuỗi trả về không bao gồm nhóm ký tự abc.
Ký tự đánh dấu
  • ^ tìm chuỗi con phù hợp nằm ở đầu chuỗi cha hoặc dòng
  • $ tìm chuỗi con phù hợp nằm ở cuối chuỗi cha hoặc dòng
  • \b tìm chuỗi con phù hợp nằm ở đầu hoặc cuối của một từ trong chuỗi gốc. Tùy thuộc vào vị trí đặt \b ở đầu hoặc cuối của chuỗi trong biểu thức.
  • \B ngược lại với \b
Ký tự chỉ số lượng
  • | toán tử hoặc
  • + lặp một ký tự hoặc một biểu thức con trước đó >=1 lần. Dạng ghi ngắn của {1,}
  • * lặp một ký tự hoặc một biểu thức con trước đó >=0 lần.  Dạng ghi ngắn của {0,}
  • ? lặp một ký tự hoặc một biểu thức con trước đó 0 hoặc 1 lần. Dạng ghi ngắn của {0,1}
  • {n}: lặp một ký tự hoặc một biểu thức con trước đó x lần 
  • {n,}: lặp một ký tự hoặc một biểu thức con trước đó >=n lần 
  • {n,m}: lặp một ký tự hoặc một biểu thức con trước đó n đến m lần
  • ? theo sau vòng lặp sẽ là tìm kiếm lười
  • \ dùng để chèn ký tự đặc biệt vào biểu thức. \t \n \r \. \\ \/ \+ \* \? \^ \$ \[ \] \{ \} \| \( \)

Ví dụ và phân tích Regex bằng hình ảnh

Sau đây là một số biểu thức hay dùng và cách đọc. Quy ước đường màu đen là đường đi, đường màu đỏ là vòng lặp.



Tìm chuỗi "TapHuan" trên toàn văn bản



Tìm chuỗi "TapHuan" trên mỗi dòng toàn văn bản và không phân biệt chữ hoa, chữ thường



Biểu thức dùng để kiểm tra mật khẩu có từ 6 đến 18 ký tự (chỉ bảo gồm số, chữ, gạch chân, và gạch ngang)
[a-z0-9_-]{6,18}



Biểu thức kiểm tra username có từ 3 đến 16 ký tự không
[a-z0-9_-]{3,16}



Tìm số điện thoại, ví dụ +84 983435230
(\+\d{2,4})?\s?(\d{10})



Kiểm tra tính hợp lệ của email
([\w\.])+@([a-zA-Z0-9\-])+\.([a-zA-Z]{2,4})(\.[a-zA-Z]{2,4})?



Tìm link cơ bản
(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?



Tìm link bao gồm luôn tham số
(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w\.\-&\?=]*)*\/?



Tìm địa chỉ IP
(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)



Tìm số Hex
#?([a-f0-9]{6}|[a-f0-9]{3})



Tìm HTML Tag
<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)



Tìm ngày dạng dd/mm/yyyy. Không đúng với năm nhuận
(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}

Trong phần 2, tôi sẽ liệt kê thêm nhiều ví dụ thực tế khác để chúng ta sử dụng và hiểu hơn về RegEx.

  • lap-trinh