Cái này là 1 thứ mà bất cứ ai làm trong ngành IT cũng đã nghe đến, nhưng mình nghĩ là mọi người nên biết cách sử dụng, chứ ko còn dừng lại ở biết.
Trang web để bạn test thử: https://regex101.com/
Nội dung bài viết
I. Regex là gì?
Là cách để tìm 1 đoạn text trong 1 đoạn văn bản nào đó bằng 1 cú pháp dựa trên các ký tự đặc biệt.
- Dev hay dùng regex để kiểm tra xem input người dùng nhập vào có chuẩn hay ko? Ví dụ như validate email, phone.
- Tester thường dùng để extract value từ HTML, JSON
- Ngoài ra, mình còn dùng để tìm file trong 1 folder, find and replace 1 vài từ trong 1 văn bản rất dài…
Ví dụ:
II. Metacharacter
Để match được thì chúng ta phải dựa vào những ký tự đặc biệt, gọi là metacharacter.
1. String literal
Có nghĩa là match trực tiếp vào ký tự mà ta mong muốn.
Ví dụ: tìm “hidden” trong đoạn text bên dưới, kết quả.
2. Character class
Bạn muốn match theo tập hợp, 1 số tập hợp cơ bản như sau:
[A-Z]
–> từ A tới Z, lưu ý viết hoa.[a-m]
–> từ a tới m, viết thường.[0-9]
–> từ 0 đến 9.[a-zA-Z0-9]
–>từ a tới z
hoặctừ A tới Z
hoặctừ 0 đến 9
.
Lưu ý, cả đoạn ngoặc vuông chỉ match vào 1 ký tự duy nhất. [A-Za-z0-9]-company
sẽ match vào e-company
chứ ko phải Google-company
.
Nếu muốn đổi ngược lại ý nghĩa chỉ cần dùng dấu (^)
. Ví dụ [^0-9]
–> ký tự nào cũng được, nhưng ko phải là số.
3. Predefined Character Classes
Nếu cái nào cũng phải tự định nghĩa ra cái character class thì mệt quá, người ta cung cấp luôn những Predefined Character Classes để có thể match nhiều thứ hơn nhưng chỉ với 1 ký tự.
- Dấu chấm (.) sẽ match vào tất cả ký tự, trừ ký tự xuống dòng (tùy điều kiện)
- Hay
\d
sẽ tương đương với các ký tự số. - Hoặc thay vì
[a-zA-Z0-9]
, ta chỉ cần\w
, ngắn gọn hơn rất nhiều.
4. Quantifiers
3 mục ở trên, giúp mình định nghĩa ra cách match vào các ký tự khác nhau, nhưng chúng ta cần phải biết là match số lượng bao nhiêu.
- Nếu bạn biết chính xác số tự ký tự, hãy dùng
{n}
,{n,m}
và{n,}
Trong đó, n và m là số lần bạn muốn.
Tôi muốn 1 pattern mà có 3 số, 1 gạch ngang, rồi có 4 số
, tôi sẽ dùng \d{3}-\d{4}
. Kết quả là nó match 555-1234
, chứ nó ko match 2222-444
.
Tôi muốn 1 pattern mà có ít nhất là 3 số, 1 gạch ngang, rồi ít nhất 5 số
, tôi sẽ dùng \d{3,}-\d{5,}
, kết quả
- Nếu bạn không biết chính xác đoạn độ dài mà bạn muốn lấy, bạn sẽ phải chọn stategy mà regex engine sẽ dùng để match cho bạn.
- Greedy: Lấy nhiều nhất có thể. Regex engine sẽ đọc toàn bộ văn bản, kiểm tra có đúng với regex ko, rồi nó lùi dần từng ký tự và lại kiểm tra.
- Reluctant: Ngược lại với Greedy, lấy ít nhất có thể. Regex engine sẽ đọc từ ký tự đầu tiên, so sánh với regex và mỗi lần lại tăng thêm 1 ký tự.
- Possessive: Luôn luôn đọc toàn bộ, kiểm tra và không lùi từng ký tự như greedy.
Làm thế nào mà bạn có thể bảo cho Regex Engine biết stategy mà bạn chọn là cái nào, đây là lúc bạn phải dùng thêm các ký tự đặc biệt khác.
Kết quả của 1 regex luôn là 1 trong 3 loại sau:
- Once or not at all (?): Một lần hoặc không lần nào (1 hoặc 0)
- Zero or more times (*): Nhiều lần hoặc không lần nào (có cũng được, ko có cũng được)
- One or more times (+): Một lần hoặc nhiều lần (ít nhất 1 lần)
Điều này sẽ kết hợp với các strategy ở trên để cho ra các cách match khác nhau:
- Greedy:
X + (?) / (*) / (+)
là được. Ví dụ:[0-9]*
–> nó có cả kết quả null hay rỗng, vì (*) thì nó sẽ match cảkhông lần nào
. =))))
- Reluctant:
greedy + (?)
- Possessive:
greedy + (+)
5. Grouping
Làm thế nào để chúng ta có thể coi cả 1 tập hợp như 1 phần tử? Đó chính là ý nghĩa của grouping, nằm trong đóng mở ngoặc tròn ()
. Ví dụ:
Cái này theo strategy Reluctant – lấy ít nhất có thể.
Nếu bạn muốn lấy toàn bộ, hãy đổi sang greedy. \d{3}-(.+)
Như trong hình, phần grouping là (.+)
là 1 bộ phận của Match, số lượng grouping trong Match là số lượng cặp đóng mở ngoặc()
.
III. Kết luận
Trên đây là 1 vài dòng note của mình về Regex, có thể nó vẫn khó hiểu với bạn nếu bạn lần đầu tiếp xúc nhưng bạn cũng không cần phải thấy nản vì ai cũng thế thôi. Câu nói nổi tiếng của Regex là “Nếu bạn có 1 vấn đề, bạn nghĩ có thể dùng regex để xử lý vấn đề đó. Bây giờ, bạn có 2 vấn đề”. =))))
Cảm ơn anh Giang nhiều vì bài chia sẻ này
You’re welcome! 🙂