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.
T | Biểu thức chính quy | Mô tả |
1 | . | Khớp (match) với bất kỳ ký tự nào |
2 | ^regex | Biểu thức chính quy phải khớp tại điểm bắt đầu |
3 | regex$ | 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. |
8 | X|Z | Tìm X hoặc Z. |
9 | XZ | Tìm X và theo sau là Z. |
10 | $ | Kiểm tra kết thúc dòng. |
11 | \d | Số bất kỳ, viết ngắn gọn cho [0-9] |
12 | \D | Ký tự không phải là số, viết ngắn gon cho [^0-9] |
13 | \s | Ký tự khoảng trắng, viết ngắn gọn cho [ \t\n\x0b\r\f] |
14 | \S | Ký tự không phải khoản trắng, viết ngắn gọn cho [^\s] |
15 | \w | Ký tự chữ, viết ngắn gọn cho [a-zA-Z_0-9] |
16 | \W | Ký 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 | \b | Ký 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