Regular Expression (Regex)

String & Regex


Thường khi bạn cần viết mã để xác thực đầu vào của người dùng, chẳng hạn như để kiểm tra xem đầu vào có phải là một số, một chuỗi với tất cả các chữ cái thường hoặc có chữ cái viết hoa. Bạn viết như thế nào loại mã này? 
Một cách đơn giản và hiệu quả để thực hiện nhiệm vụ này là sử dụng biểu thức chính quy (Regex).

Regular Expression hay còn gọi là biểu thức chính quy (viết tắt Regex) là một chuỗi mô tả một mẫu các điều kiện để so khớp với chuỗi đầu vào. Biểu thức chính quy là một công cụ mạnh mẽ cho các thao tác chuỗi. Bạn có thể dùng biểu thức chính quy để khớp, thay thế và tách chuỗi. 

So khớp chuỗi 

Hãy bắt đầu với phương thức Matches trong lớp String. Nhìn ví dụ dưới, thoạt nhìn matches tương tư như equals.

"Java".matches("Java");

"Java".equals("Java");

Tuy nhiên matches mạnh mẽ hơn, nó không chỉ so khớp một chuỗi cố định mà còn so khớp một chuỗi theo mẫu. Các ví dụ dưới đều cho kết quả là true.

"Java is fun".matches("Java.*")
"Java is cool".matches("Java.*")
"Java is powerful".matches("Java.*")

“Java.*” trong câu lệnh là một biểu thức chính quy, nó mô tả một chuỗi bắt đầu bằng “Java”, đằng sau là một chuỗi hoặc ko có ký tự nào


 boolean a = "Java is fun".matches("Java.*");
        boolean b = "Java is cool".matches("Java.*");
        boolean c = "Java is powerful".matches("Java.*");

        System.out.println("a:" +  a);
        System.out.println("b:" +  b);
        System.out.println("c:" +  c);

Kết quả:

Cú pháp biểu thức chính quy

Một biểu thức chính quy bao gồm các ký tự nguyên thủy và các ký hiệu đặc biệt.Phía dưới là bảng liệt kê một số cú pháp được sử dụng thường xuyên cho các biểu thức thông thường.

TBiểu thức chính quyMô tả
1.Khớp (match) với bất kỳ ký tự nào
2^regexBiểu thức chính quy phải  khớp tại điểm bắt đầu
3regex$Biểu thức chính quy phải khớp ở cuối dòng.
4[abc]Thiết lập định nghĩa, có thể khớp với a hoặc b hoặc c.
5[abc][vz]Thiết lập định nghĩa, có thể khớp với a hoặc b hoặc c theo sau là v hay z.
6[^abc]Khi dấu ^ xuất hiện như là nhân vật đầu tiên trong dấu ngoặc vuông, nó phủ nhận mô hình. Điều này có thể khớp với bất kỳ ký tự nào ngoại trừ a hoặc b hoặc c.
7[a-d1-7]Phạm vi: phù hợp với một chuỗi giữa a và điểm d và con số từ 1 đến 7.
8X|ZTìm X hoặc Z.
9XZTìm X và theo sau là Z.
10$Kiểm tra kết thúc dòng.
 
11\dSố bất kỳ, viết ngắn gọn cho [0-9]
12\DKý tự không phải là số, viết ngắn gon cho [^0-9]
13\sKý tự khoảng trắng, viết ngắn gọn cho [ \t\n\x0b\r\f]
14\SKý tự không phải khoản trắng, viết ngắn gọn cho [^\s]
15\wKý tự chữ, viết ngắn gọn cho [a-zA-Z_0-9]
16\WKý tự không phải chữ, viết ngắn gọn cho [^\w]
17\S+Một số ký tự không phải khoảng trắng (Một hoặc nhiều)
18\bKý tự thuộc a-z hoặc A-Z hoặc 0-9 hoặc _, viết ngắn gọn cho [a-zA-Z0-9_].
 
19*Xuất hiện 0 hoặc nhiều lần, viết ngắn gọn cho {0,}
20+Xuất hiện 1 hoặc nhiều lần, viết ngắn gọn cho {1,}
21?Xuất hiện 0 hoặc 1 lần, ? viết ngắn gọn cho {0,1}.
22{X}Xuất hiện X lần, {}
23{X,Y}Xuất hiện trong khoảng X tới Y lần.
24*?* có nghĩa là xuất hiện 0 hoặc nhiều lần, thêm ? phía sau nghĩa là tìm kiếm khớp nhỏ nhất.

Ví dụ:

Định nghĩa một regex

\d{1,2}[-|/]\d{1,2}[-|/]\d{4}

\d{1,2}: nghĩa là một số có 1 hoặc 2 chữ số (ngày và tháng).
[-|/]: nghĩa là ký tự - hoặc /.
\d{4}: nghĩa là một số có 4 chữ số (năm)
String text1 = "Hello java regex 2-12-2018, hello world 12/12/2018";
Pattern pattern = Pattern.compile("\\d{1,2}[-|/]\\d{1,2}[-|/]\\d{4}");
Matcher matcher = pattern.matcher(text1);
System.out.println("Ngày tháng trong chuỗi text1: " + text1);
while (matcher.find()) {
    System.out.println(text1.substring(matcher.start(), matcher.end()));
}
String text2 = "2/12/2018";
String text3 = "12/12/aaaa";
pattern = Pattern.compile("^\\d{1,2}[-|/]\\d{1,2}[-|/]\\d{4}$");
System.out.println("\nChuỗi " + text2 + " có định dạng ngày tháng: "
        + pattern.matcher(text2).matches());
System.out.println("Chuỗi " + text3 + " có định dạng ngày tháng: "
        + pattern.matcher(text3).matches());

 Kết quả:

Thay thế và tách chuỗi

Ngoài phương thức matches để so khớp chuỗi, Lớp String còn bao gồm các phương thức replaceAll, replaceFirst, và split để thay thế và cắt chuỗi bằng biểu thức chính quy

+matches(regex: String): boolean

+replaceAll(regex: String, replacement: String): String

+replaceFirst(regex: String, replacement: String): String

+split(regex: String): String[]

+split(regex: String, limit: int): String[]

System.out.println("Java Java Java".replaceAll("v\\w", "wi"));
Kết quả : Jawi Jawi Jawi
System.out.println("Java Java Java".replaceFirst("v\\w", "wi"));
Kết quả: Jawi Java Java

Sử dụng java.util.regex.Pattern và java.util.regex.Matcher

Pattern là một đối tượng mẫu, một phiên bản đã được biên dịch của một biểu thức chính quy. Nó không có cấu tử (constructor) public, và chúng ta sẽ sử dụng method tĩnh compile(String) để tạo đối tượng, với tham số là biểu thức chính quy.

Matcher là một phương tiện để so khớp chuỗi dữ liệu đầu vào với đối tượng Pattern đã được tạo ra ở trên. Class này không có cấu tử public, và chúng ta lấy đối tượng này thông qua method matcher(String) của đối tượng Pattern. Với tham số đầu vào String là văn bản cần kiểm tra.

PatternSyntaxException sẽ bị ném ra một ngoại lệ (excepton) nếu biểu thức chính quy có ngữ pháp không chính xác.


String str = "Welcome   to gpcoder";
         
// Ký tự bất kỳ xuất hiện nhiều lần lần và kết thúc là r
String regex = ".*r$";
 
// Tạo đối tượng Pattern thông qua method tĩnh.
Pattern pattern = Pattern.compile(regex);
 
// Lấy ra đối tượng Matcher
Matcher matcher = pattern.matcher(str);
 
// Kiểm tra có khơp với regex không
boolean match = matcher.matches();
System.out.println("Match = " + match); // Match = true

Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Leave a Reply

Your email address will not be published. Required fields are marked *