Hướng dẫn Regular Expressions - Biểu thức chính quy

  • Chào bạn, hãy đăng ký hoặc đăng nhập để tham gia cùng bọn mình và sử dụng được đầy đủ chức năng của diễn đàn :).

Bạn đã biết tới Regular Expressions trước khi đọc bài viết này?


  • Total voters
    44
Trạng thái
Đã bị khoá.

quachtridat

HEROBRINE
25/7/16
11
7
130
21
Bien Hoa, Dong Nai, Vietnam
Regular Expressions
Biểu thức chính quy


Đây là 1 khái niệm có thể mới hoặc ít được sử dụng đối với nhiều người, nhưng lợi ích & ứng dụng của nó vô cùng to lớn. Mình học hiểu được cái này qua course regular expressions ở Hackerrank (trang học code vừa hay vừa miễn phí <3) và muốn chia sẻ với mọi người về regular expressions.
Hãy coi video dưới đây để biết tại sao mình nói "lợi ích & ứng dụng của nó vô cùng to lớn". Bạn có thể skip tới 1:03 để xem:
  1. Giới thiệu về regular expressions (RegEx)
    • Regular expressions (biểu thức chính quy) (viết tắt là RegEx, RegExp, RegXp, RegExpr, ...) là một chuỗi ký tự đặc biệt được dùng làm mẫu (pattern) để phân tích sự trùng khớp của một tập hợp các chuỗi nào đó. Nói cách khác, biểu thức chính quy là các patterns dùng để nhận diện các chuỗi kí tự phù hợp với patterns đưa ra.​
    • Regular expressions được sử dụng nhiều trong các ngôn ngữ lập trình như Java (java.util.regex), C# (System.Text.RegularExpressions), Python (re), ... Hầu hết các ngôn ngữ lập trình hiện nay đều có các hàm để xử lí regular expressions. Mình đã sử dụng Java 8 trong toàn bộ thời gian học RegEx ở Hackerrank.​
  2. RegEx được dùng để làm gì?
    • Thao tác với, hoặc kiểm tra tính hợp lệ của địa chỉ email, số điện thoại, username, password, ngày tháng năm, thời gian và các chuỗi kí tự đầu vào theo định dạng nhất định.​
    • Cải tiến find & replace trong các phần mềm như MS Word, các text editor, các IDE như IntelliJ IDEA, Microsoft Visual Studio, VS Code, ...​
    • Được dùng trong các bộ máy tìm kiếm.​
  3. Cú pháp & một số công cụ kiểm tra cú pháp
    1. Literal characters (kí tự thường): Nếu pattern chỉ chứa kí tự thường thì RegEx được xử lí như chức năng find mặc định. Ví dụ:​
      • Pattern là "hello" thì khớp với các lần xuất hiện của "hello" trong các từ như hello, helloworld, sayhello, hellohello.​
      • Pattern là "tab" thì khớp với các lần xuất hiện của "tab" trong các từ như tab, tablet, establish, table, tabs.​
    2. Meta-characters (kí tự siêu): Các kí tự này có các chức năng riêng. Dưới đây mình mô tả ý nghĩa của các meta-char thường dùng, còn đầy đủ thì hãy tự tìm hiểu trên mạng:​
      • [?]: Khớp với bất kì kí tự nào giữa dấu 2 ngoặc vuông. Ví dụ:​
        • Pattern là "m[aeiou]ster" thì khớp với các lần xuất hiện của "m?ster" (với ? là 1 trong các kí tự a, e, i, o, u) trong các từ như: master, mester, mister, moster, muster, mistermaster.​
        • Pattern là "[123456abcdef]" khớp với các lần xuất hiện của "?" (với ? là 1 trong các kí tự 1, 2, 3, 4, 5, 6, a, b, c, d, e, f) trong các từ: 65ag, ab567.​
      • ?-?: Chỉ tất cả các kí tự từ kí tự đặt ở dấu ? đầu tiên tới dấu ? thứ 2, với điều kiện mã ASCII của kí tự ở dấu ? đầu tiên không lớn hơn mã ASCII của kí tự ở dấu ? thứ 2, có tác dụng khi đặt trong ngoặc vuông. Ví dụ:​
        • Pattern là "[a-z][0-9]" thì khớp với các lần xuất hiện của "??" (với ? thứ nhất là 1 trong các kí tự từ a tới z, và ? thứ 2 là 1 trong các kí tự từ 0 tới 9) trong các từ như: a1, b2, c5, e7, u0, f8.​
        • Pattern là "[A-Za-z0-9][ab12]" thì khớp với các lần xuất hiện của "??" (với ? thứ nhất là 1 trong các kí tự từ A tới Z hay từ a tới z hay từ 0 tới 9, và ? thứ 2 là một trong các kí tự a, b, 1, 2) trong các từ như: Aa, B1, c2, da, 01, 92, 71, ca, z2.​
      • ^?: Chỉ tất cả các kí tự không phải kí tự được liệt kê sau nó, có tác dụng khi đặt trong ngoặc vuông và đứng ngay sau dấu ngoặc vuông mở. Ví dụ:​
        • Pattern là "[^A-Za-z]" thì khớp với các lần xuất hiện của "?" (với ? không phải là 1 trong các kí tự từ A tới Z hay từ a tới z) trong các từ như: 1, 2, 3, @, !, $, %.​
      • ^?: Chỉ (các) kí tự đầu tiên ở trong chuỗi kí tự, có tác dụng ngoài dấu ngoặc vuông. Ví dụ:​
        • Pattern là "^a" thì khớp với kí tự a đầu tiên trong các từ như: abc, a12, antivirus, aaaaaaaa.​
        • Pattern là "^123" thì khớp với cụm kí tự 123 đầu tiên trong các từ như: 123456, 123abc, 123123.​
      • ?$: Chỉ (các) kí tự cuối cùng ở trong chuỗi kí tự được liệt kê ở dấu ?. Ví dụ:​
        • Pattern là "KKK$" thì khớp với cụm kí tự KKK cuối cùng trong các từ như: KKKKKK, BBBKKK, KoolKidKlubKKK.​
      • ?+: Khớp với 1 hoặc nhiều lần kí tự đặt ở dấu ?. Ví dụ:​
        • Pattern là "hj+t" thì khớp với các lần xuất hiện của cụm kí tự "h?t" (với ? là 1 hoặc nhiều kí tự j) trong các từ như: hjt, ohshjjjjjjjjjjjjjjjjjjjjjt.​
        • Pattern là "b[au]+k[ua]+" thì khớp với các lần xuất hiện của cụm kí tự "b?k?" (với ? thứ nhất là 1 hoặc nhiều lần kí tự a hoặc u, ? thứ 2 là 1 hoặc nhiều lần kí tự u hoặc a) trong các từ như: bakaaaaaaaaaa, buku.​
      • ?*: Khớp với 0 hoặc 1 hoặc nhiều lần kí tự đứng trước nó. Ví dụ tương tự như trên nhưng vẫn khớp với các từ như: ht, fuckinwowsht, bk.​
      • ??: Khớp với 0 hoặc 1 lần những gì đặt ở dấu ?.​
      • . khớp với bất kì kí tự nào trừ kí từ xuống dòng (CR, LF).​
      • ?{n}: Khớp với đúng n lần xuất hiện của kí tự đặt ở dấu ? (với n không âm). Ví dụ:​
        • Pattern là "6{3}" thì khớp với các lần xuất hiện của 666 trong các từ như: 666AintSatan, 66666, get666.​
      • ?{n,}: Khớp với ít nhất n lần xuất hiện của kí tự đặt ở dấu ? (với n không âm). Ví dụ:​
        • Pattern là "10{2}" thì khớp với các lần xuất hiện của "1?" (với ? là 2 hoặc nhiều hơn 2 kí tự 0) trong các từ như: 100, 1000, million1000000.​
      • ?{n,m}: Khớp với it nhất n và nhiều nhất m lần xuất hiện của kí tự đặt ở dấu ? (với n & m không âmn nhỏ hơn hoặc bằng m).​
      • ?|?: Khớp với những gì ở dấu ? thứ nhất hoặc những gì ở dấu ? thứ 2. Ví dụ​
        • Pattern là "[a-z-]+|[2-7]gud[4-9]me" khớp với các lần xuất hiện của "?" (với ? là 1 hay nhiều kí tự trong khoảng từ a tới z hoặc kí tự -) hay các lần xuất hiện của "?gud?me" (với ? thứ nhất là kí tự trong khoảng từ 2 tới 7, ? thứ 2 là kí tự trong khoảng từ 4 tới 9) trong các từ như: sagiri-chan 2gud4me, regex 3gud5me, abc-def, 7gud9me.​
      • ?\b hoặc \b? (word boundary): Khớp với những gì ở dấu ? với điều kiện đứng sau nó hoặc đứng trước nó phải là 1 từ. Ví dụ: Pattern "hello\b" sẽ khớp với "hello" trong hello world, hello everybody nhưng không trong helloworld, hellofriend.​
      • ?\B hoặc \B?: Ngược với bên trên.​
      • \d (digit): Khớp với các kí tự số (từ 0 tới 9). Ví dụ:​
        • Pattern là "\d+" thì khớp với các lần xuất hiện của 1 hay nhiều chữ số trong các từ như: 123456, 1, abc123.​
      • \D (non-digit): Ngược với bên trên, khớp với các kí tự không phải số.​
      • \w (word): Khớp với các kí tự chữ cái (từ A tới Z, từ a tới z và dấu _ (underscore)).​
      • \W (non-word): Ngược với bên trên.​
      • \u???? (Unicode): Khớp với kí tự có mã Unicode là cụm 4 chữ hoặc số đặt trong 4 dấu ?. VD các pattern hợp lệ: "\u00AF", "\u0000", "\uFFFF".​
      • (?): Đặt những gì ở dấu ? vào trong 1 nhóm, phục vụ cho nhu cầu sử dụng lại.​
      • (?:?) Đặt những gì ở dấu ? vào trong 1 nhóm, nhưng không phục vụ cho nhu cầu sử dụng lại, chỉ để gom nhóm thôi.​
      • \? (với ?số nguyên dương): Chỉ nhóm có số thứ tự là ?. Ví dụ: Pattern là "^(\w+)\1$" khớp với các xâu kí tự như: abab, aa, bb, cDe_cDe_.
      • \? (với ?kí tự khác chữ và số): Biến kí tự ở dấu ? thành kí tự bình thường, tránh trùng với kí tự của bộ máy xử lí RegEx. Ví dụ khi gõ kí tự (, ), [, ], {, }, . mà muốn tránh trùng với các meta-char như trên thì viết \(, \), \[, \], \{, \}, \. là được.​
    3. Một số công cụ kiểm tra cú pháp RegEx:
      • Web: Có RegExr, RegExPal và vô vàn các trang web khác. Cá nhân mình đánh giá cao RegExr vì giao diện dễ nhìn, thân thiện, có cheat-sheet & quick reference, có hightlight tốt, liệt kê các match, hiển thị tác dụng đầy đủ của các meta-char. Mọi bài tập RegEx khi học ở Hackerrank mình đều dùng RegExr làm công cụ hỗ trợ check syntax.​
      • Dùng Visual Studio thì có thể cài một số phần mở rộng (extensions). Riêng mình thì recommend ReSharper của bên JetBrains nếu có tiền, vì bên cạnh hỗ trợ check syntax RegEx ngon thì còn vô vàn hỗ trợ tốt, ví dụ như refactor code.​
      • IntelliJ IDEA nhớ không lầm là có sẵn check RegEx luôn rồi.​
  4. Ứng dụng: Khi viết code, thay vì phải dùng vòng lặp như hồi học lập trình lớp 8, lớp 11, thì ta có thể đưa RegEx vào, vừa đỡ sợ thiếu sót (vì đã được test & cải thiện qua nhiều năm), vừa linh hoạt & dễ chỉnh sửa (chỉ cần thay pattern(s) & flags), lại giảm được số dòng code (chỉ cần gọi hàm xử lí RegEx thay vì gõ 1 đống vòng lặp), profit :D. Dưới đây là một số ứng dụng phổ biến hoặc có thể hữu ích cả khi viết code về plugin cho Minecraft servers:​
    1. Địa chỉ email hợp lệ có dạng [email protected], như [email protected], [email protected]. Phần username chứa ít nhất 1 kí tự chữ, có thể có dấu chấm và dấu gạch dưới (underscore). Phần tên miền cũng tương tự tên miền trang web.
      Sample code:
      PHP:
      [\w\.]+\@\w+(?:\.\w+)+
    2. Username hợp lệ không chứa khoảng cách, chỉ có các kí tự chữ số và gạch dưới, thường có độ dài nhỏ nhất là 3.
      Sample code:
      PHP:
      ^[\w\d]{3,}$
    3. Địa chỉ trang web có thể có hoặc không cần phần protocol http:// và nếu có thì có thể là https:// cũng phù hợp, sau đó có thể có phần www. hoặc có thể không, rồi tới phần tên miền chính như abc.com, minecraftvn.net, ez.tk, có thể có cả dấu gạch ngang và số trong tên miền như 001webhosting.com, git-gud.vn, sau đó có thể có dấu / hoặc không, rồi sau đó có thể có các sub-directory (buộc phải có dấu / phân cách trước mỗi sub-dir), các sub-dir còn có thể có dấu chấm, như minecraftvn.net/forum/lap-trinh.f51, rồi cuối cùng có thể có extension như .html, .php, .htm, .aspx. Các dấu / phân cách thường không có trường hợp đứng liền nhau.
      Sample code:
      PHP:
      (?:(?:https?\:\/\/)?(?:www\.)?((?:[A-Za-z0-9-]+\.)+[A-Za-z0-9-]+)(?:\/[A-Za-z0-9-]+(?:\.[A-Za-z0-9]+)*)*\/?)
    4. Giả sử công việc của bạn là viết hàm thay thế các color & format tags dạng như &a, &b, &c trong 1 string thành §a, §b, §c mà chỉ thay các color & format ID của Minecraft, không thay thế các cái khác như &j, &q hay dấu &, &!, &&, và có thể ở dạng khác như ?a, ?b, ?c, về §a, §b, §c. Đây là pattern nhận diện cho trường hợp string có color & format tags dạng như &a, &b, &c. Pattern này sẽ so khớp các đoạn string bắt đầu bằng kí tự & và theo sau là kí tự chữ số hoặc kí tự chữ cái từ a tới f hay từ k tới o.
      PHP:
      &[0-9a-fk-o]
      Giờ thì chỉ cần dùng hàm replace của string để thay thế hết chúng nó thôi.
      Nếu thao tác với Java thì: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#replaceAll-java.lang.String-java.lang.String-
      Kí tự tag khác thì viết hàm rồi ghép nó thành string làm thành pattern rồi đẩy vào hàm replace thôi :D

      Hay công việc của bạn là detect Minecraft item name, literal name hay ID của nó. Các ví dụ hợp lệ là Bed, Apple, minecraft:golden_sword, minecraft:stone, 1, 2, 1:1, 137, Enchantment Table, Skull:2, Command Block:1. Item name thường thì chỉ có chữ, có thể có data id theo sau phân cách bằng dấu 2 chấm. Literal name thì có minecraft: trước nó và không có space, các kí tự sau minecraft: chỉ có thể là chữ cái viết thường hoặc dấu _. ID thì là số, có thể có data id theo sau phân cách bằng 2 chấm.
      Sample pattern cho item name & ID có hoặc không kèm data id:
      PHP:
      ^(\d+|[A-Za-z]+(?:(?:\ +[A-Za-z]+)*|(?:_*[A-Za-z]+)*))(?:(?:\:)(\d+))?$
      Từ item name sang literal name thì chỉ việc lowercase, xoá khoảng trắng dư thừa, thay các kí tự khoảng trắng thành dấu gạch dưới (underscore) rồi thêm minecraft: vào đầu thôi.

Tóm lại, khi nhắc tới RegEx, hãy nghĩ ngay tới những chuỗi kí tự có dạng \w, ^[A-Za-z0-9]\w+(\d)\1\1(?:ABC|ABCD)*$, \s\S là những pattern, để nhận diện những chuỗi kí tự con trong các chuỗi kí tự khác. RegEx rất hữu ích để làm bộ máy kiểm tra tính hợp lệ của xâu kí tự (string) ở các trang web (textboxes, forms, etc.) và trong việc tìm kiếm những chuỗi kí tự không cố định trong văn bản.

Mình dừng bài viết ở đây. Nếu có gì thắc mắc thì có thể tra Google. Nội dung có thiếu thừa hay sai sót thì mong mọi người góp ý. Cảm ơn các bạn đã quan tâm.

Nguồn tham khảo: https://passionery.blogspot.com/2014/10/regular-expression-bieu-thuc-chinh-quy-la-gi.html
Đọc thêm: https://trachanhso.net/regular-expression-bieu-thuc-chinh-quy/
 
Chỉnh sửa cuối:
  • Like
Reactions: Shuu

RemVN

DEVELOPER
THÀNH VIÊN
28/3/17
260
1,392
550
20
Việt nam
Cái này hay nhỉ :hm4: chắc ngồi mò thử
 

anhcraft

BAN QUẢN TRỊ
DEVELOPER
DONATOR
THÀNH VIÊN
18/9/16
2,231
2,891
940
.
anhcraft.dev
regexp cũng biết chút chút :v nhìn ban đầu rối vcl
mà...thường có mấy lib rùi nên chắc dùng cái này cũng ít
tks đã chia sẻ =))
 

quachtridat

HEROBRINE
25/7/16
11
7
130
21
Bien Hoa, Dong Nai, Vietnam
Tr đất comeback r hả ông
Not really.
Cái này hay nhỉ chắc ngồi mò thử
Hay mà :>
regexp cũng biết chút chút nhìn ban đầu rối vcl
mà...thường có mấy lib rùi nên chắc dùng cái này cũng ít
tks đã chia sẻ
Đúng là nhìn ban đầu rối thật, nhưng ai đời validate string format bằng vòng lặp, giờ học vừa biết thêm vừa đỡ tốn thời gian gõ :v
Libraries thì cũng về RegEx, ít người quen thao tác thôi.
 

RemVN

DEVELOPER
THÀNH VIÊN
28/3/17
260
1,392
550
20
Việt nam
Not really.

Hay mà :>

Đúng là nhìn ban đầu rối thật, nhưng ai đời validate string format bằng vòng lặp, giờ học vừa biết thêm vừa đỡ tốn thời gian gõ :v
Libraries thì cũng về RegEx, ít người quen thao tác thôi.
Viết tắt nhiều quá đôi lúc cũng rối vl ra =))
 

quachtridat

HEROBRINE
25/7/16
11
7
130
21
Bien Hoa, Dong Nai, Vietnam
Viết tắt nhiều quá đôi lúc cũng rối vl ra
Nếu đang nói về RegEx thu lại bằng các meta-char nhìn như viết tắt thì bù lại RegEx có format chuẩn, chứ không viết tắt vô tội vạ như hay viết trên sách vở hay t33nc0d3. Học biết RegEx rồi thì không cảm thấy khó hiểu, mà vừa không khó hiểu, code ngắn gọn không rườm rà mà vẫn đảm bảo chương trình chạy tốt thì ngại gì không dùng. Ai đọc code mà không hiểu thì cũng phải tự mò học thôi eks dee.
 

Banbeucmas

DEVELOPER
WIBU
THÀNH VIÊN
F TO PAY RESPECT
HEROBRINE
12/7/16
9,991
1,444
950
19
Hà Nội, Việt Nam

anhcraft

BAN QUẢN TRỊ
DEVELOPER
DONATOR
THÀNH VIÊN
18/9/16
2,231
2,891
940
.
anhcraft.dev
hỏi chủ top cái =]]
check double thế này đúng k =]] hay là dài quá nhỉ :|
((-|)([0-9]+\\.[0-9]+))|((-|)([0-9]+[0-9]+))
 

quachtridat

HEROBRINE
25/7/16
11
7
130
21
Bien Hoa, Dong Nai, Vietnam
hỏi chủ top cái =]]
check double thế này đúng k =]] hay là dài quá nhỉ
((-|)([0-9]+\\.[0-9]+))|((-|)([0-9]+[0-9]+))
Kiểm tra string có phải real number không ấy à? Nếu đang code thì ném cho parser rồi catch exception hoặc boolean isDecimal là được mà :| Cái gì sẵn thì cứ tận dụng trước đã.
Nếu kiểm tra số nguyên/thực thì chỉ cần thế này:
PHP:
-?\d+(?:\.\d+)?
 
  • Like
Reactions: anhcraft
Trạng thái
Đã bị khoá.