Regular Expression trong Java

Java cung cấp java.util.regex package cho pattern so khớp với các Regular Expression. Các Regular Expression trong Java là tương tự với Ngôn ngữ lập trình Perl và rất dễ dàng để học.

Một Regular Expression là một dãy liên tục của các ký tự đặc biệt mà giúp bạn so khớp hoặc tìm kiếm chuỗi hoặc tập hợp các chuỗi khác, sử dụng một cú pháp riêng biệt trong một pattern. Chúng có thể được sử dụng để tìm, chỉnh sửa và thao tác text và dữ liệu.

Gói java.util.regex chủ yếu chứa 3 lớp sau:

  • Lớp Pattern: Một đối tượng Pattern là một phép biểu diễn được biên dịch của một Regular Expression. Lớp Pattern không cung cấp một public constructor nào. Để tạo một pattern, bạn đầu tiên phải gọi một trong các phương thức biên dịch static chung của nó, mà sau đó sẽ trả về một đối tượng Pattern. Những phương thức này chấp nhận một Regular Expression như là tham số đầu tiên.
  • Lớp Matcher: Một đối tượng Matcher là phương tiện mà thông dịch pattern và thực hiện so khớp các hoạt động với một chuỗi đầu vào. Như lớp Pattern, Matcher không định nghĩa một public constructor nào. Bạn nhận được một đối tượng Matcher bằng việc gọi phương thức matcher trên một đối tượng Pattern.
  • PatternSyntaxException: Một đối tượng PatternSyntaxException là một exception (ngoại lệ) chưa được kiểm tra mà chỉ dẫn một lỗi cú pháp trong mẫu Regular Expression.

Capture các Group trong Java

Capturing Groups là một cách coi nhiều ký tự như là một đơn vị đơn. Chúng được tạo bằng việc xác định vị trí của các ký tự để được nhóm vào trong một tập hợp các dấu ngoặc đơn. Ví dụ, Regular Expression (dog) tạo một group đơn chứa các chữ cái là "d", "o" và "g".

Capturing Groups được đánh số bởi việc tính toán số dấu ngoặc đơn mở từ trái qua phải. Ví dụ, trong Expression ((A)(B(C))) có 4 nhóm:

  • ((A)(B(C)))
  • (A)
  • (B(C))
  • (C)

Để tìm bao nhiêu group có mặt trong Expression đó, bạn gọi phương thức groupCount trên một đối tượng Matcher. Phương thức groupCount trả về một int minh họa số Capturing Groups có mặt trong mẫu của đối tượng Matcher.

Cũng có một group đặc biệt, là group 0, mà luôn luôn biểu diễn toàn bộ expression. Group này không được bao gồm trong kết quả của phương thức groupCount.

Ví dụ:

Ví dụ sau minh họa cách để tìm một chuỗi chữ số từ chuỗi chữ-số đã cho:

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegexMatches
{
    public static void main( String args[] ){


      // String de duoc quet de tim pattern.
      String line = "Vietjack xin chao cac ban. Day la vi du ve Regex! 1000  0USD";
      String pattern = "(.*)(\\d+)(.*)";


      // Tao mot doi tuong Pattern
      Pattern r = Pattern.compile(pattern);


      // Tao doi tuong matcher.
      Matcher m = r.matcher(line);
      if (m.find( )) {
         System.out.println("Gia tri duoc tim thay la: " + m.group(0) );
         System.out.println("Gia tri duoc tim thay la: " + m.group(1) );
         System.out.println("Gia tri duoc tim thay la: " + m.group(2) );
      } else {
         System.out.println("Khong co ket noi");
      }
   }
}

Nó sẽ cho kết quả sau:

Gia tri duoc tim thay la: Vietjack xin chao cac ban. Day la vi du ve Regex! 1000  0USD
Gia tri duoc tim thay la: Vietjack xin chao cac ban. Day la vi du ve Regex! 1000  
Gia tri duoc tim thay la: 0

Cú pháp cho Regular Expression trong Java

Bảng dưới đây liệt kê tất cả các cú pháp siêu ký tự cho Regular Expression có sẵn trong Java.

SubexpressionSo khớp
^So khớp với phần bắt đầu của dòng (line)
$So khớp với phần cuối của dòng
.So khớp với bất kỳ ký tự đơn nào ngoại trừ newline (dòng mới). Sử dụng tùy chọn m cũng cho phép nó so khớp với newline (dòng mới)
[...]So khớp với bất kỳ ký tự đơn nào trong dấu ngoặc vuông
[^...]So khớp với bất kỳ ký tự đơn nào không trong dấu ngoặc vuông
\APhần bắt đầu của cả chuỗi
\zPhần cuối của cả chuỗi
\ZPhần cuối của cả chuỗi
re*So khớp với 0 hoặc nhiều sự xuất hiện của expression đặt trước
re+So khớp với 1 hoặc nhiều của cái gì đó ở trước
re?So khớp với 0 hoặc 1 sự xuất hiện của expression đặt trước
re{ n}So khớp một cách chính xác với n lần xuất hiện của Expression đặt trước
re{ n,}So khớp với n lần xuất hiện hoặc nhiều hơn của Expression đặt trước
re{ n, m}So khớp với ít nhất n và nhiều nhất m lần xuất hiện của Expression đặt trước
a| bSo khớp với hoặc a hoặc b
(re)Nhóm các Regular Expression và ghi nhớ text đã so khớp
(?: re)Nhóm các Regular Expression mà không ghi nhớ text đã so khớp
(?> re)So khớp với patter độc lập mà không truy tích ngược (backtrack)
\wSo khớp với các ký tự từ
\WSo khớp với các ký tự không phải từ
\sSo khớp với khoảng trống trắng. Tương đương với [\t\n\r\f].
\SSo khớp với các ký tự không là khoảng trống trắng
\dSo khớp với các chữ số. Tương đương với [0-9].
\DSo khớp với ký tự không là chữ số
\ASo khớp với phần bắt đầu của chuỗi
\ZSo khớp với phần kết thúc của chuỗi. Nếu một newline (dòng mới) tồn tại, nó so khớp với ngay trước newline (dòng mới).
\zSo khớp với phần kết thúc của chuỗi
\GSo khớp với điểm, nơi mà so khớp cuối cùng kết thúc
\nTham chiếu ngược để capture group số "n"
\bSo khớp với các giới hạn từ bên ngoài dấu ngoặc vuông. So khớp với phím lùi (0x08) khi ở trong dấu ngoặc vuông
\BSo khớp các giới hạn không phải từ
\n, \t, etc.So khớp với các newline (dòng mới), carriage return, tab, …
\QThoát (trích dẫn) tất cả ký tự tới \E
\EKết thúc trích dẫn bắt đầu từ \Q

Các phương thức của lớp Matcher trong Java

Dưới đây là danh sách các phương thức hữu ích:

Các phương thức về Index trong Java

Các phương thức về index cung cấp các giá trị chỉ mục hữu ích giúp tìm kiếm sự so khớp chính xác trong chuỗi đầu vào.

STTPhương thức và Miêu tả
1public int start()

Trả về chỉ mục bắt đầu của so khớp trước

2public int start(int group)

Trả về chỉ mục bắt đầu của dãy phụ được nắm bắt bởi group đã cho trong hoạt động so khớp trước.

3public int end()

Trả về offset sau ký tự cuối cùng được so khớp

4public int end(int group)

Trả về offset sau ký tự cuối cùng của dãy phụ được nắm bắt bởi group đã cho trong hoạt động so khớp trước

Các phương thức Study trong Java

Các phương thức Study duyệt lại chuỗi input và trả về một Boolean chỉ rằng có hay không pattern được tìm thấy.

STTPhương thức và Miêu tả
1public boolean lookingAt()

So khớp với dãy input, bắt đầu từ khu vực đó, với pattern

2public boolean find()

Tìm dãy tiếp theo của dãy input mà so khớp với pattern

3public boolean find(int start

Đặt lại Matcher này và sau đó cố gắng tìm dãy tiếp theo của dãy input mà so khớp với pattern, bắt đầu từ chỉ mục đã xác định

4public boolean matches()

So khớp toàn bộ khu vực với pattern

Các phương thức thay thế vị trí trong Java

Các phương thức này rất hữu ích để thay thế text trong một chuỗi input:

STTPhương thức và Miêu tả
1public Matcher appendReplacement(StringBuffer sb, String replacement)

Triển khai một bước phụ thêm-và-thay thế có giới hạn

2public StringBuffer appendTail(StringBuffer sb)

Triển khai một bước phụ thêm-và-thay thế không giới hạn

3public String replaceAll(String replacement)

Thay thế mỗi dãy phụ của dãy input mà so khớp pattern với chuỗi thay thế đã cho

4public String replaceFirst(String replacement)

Thay thế dãy phụ đầu tiên của dãy input mà so khớp pattern với chuỗi thay thế đã cho

5public static String quoteReplacement(String s)

Trả về một String thay thế cho String đã xác định. Phương thức này tạo một String mà sẽ làm việc như là một sự thay thế literal trong phương thức appendReplacement của lớp Matcher.

Ví dụ về Metacharacter

import java.util.regex.*;  
class RegexExample5{  
public static void main(String args[]){  
System.out.println("cac metacharacter d....");//d nghia la ky so (digit) 


System.out.println(Pattern.matches("\\d", "abc"));//false (non-digit)  
System.out.println(Pattern.matches("\\d", "1"));//true (digit va xuat hien mot lan)  
System.out.println(Pattern.matches("\\d", "4443"));//false (digit nhung xuat hien nhieu hon mot lan)  
System.out.println(Pattern.matches("\\d", "323abc"));//false (digit va char)  


System.out.println("cac metacharacter D....");//D nghia la khong phai ky so (non-digit)  


System.out.println(Pattern.matches("\\D", "abc"));//false (non-digit nhung xuat hien nhieu hon mot lan)  
System.out.println(Pattern.matches("\\D", "1"));//false (digit)  
System.out.println(Pattern.matches("\\D", "4443"));//false (digit)  
System.out.println(Pattern.matches("\\D", "323abc"));//false (digit va char)  
System.out.println(Pattern.matches("\\D", "m"));//true (non-digit va xuat hien mot lan)  


System.out.println("cac metacharacter D voi quantifier....");  
System.out.println(Pattern.matches("\\D*", "mak"));//true (non-digit va co the xuat hien 0 hoac nhie lan)  


}}  


-------------------------------------------------------


cac metacharacter d....
false
true
false
false
cac metacharacter D....
false
false
false
false
true
cac metacharacter D voi quantifier....
true

Các phương thức startend trong Java

Ví dụ đơn giản sau tính toán số lần mà từ "cats" xuất hiện trong chuỗi input:

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegexMatches
{
    private static final String REGEX = "\\bplay\\b";
    private static final String INPUT =
                                    "play play play football tennis play";


    public static void main( String args[] ){
       Pattern p = Pattern.compile(REGEX);
       Matcher m = p.matcher(INPUT); // Lay mot doi tuong matcher
       int count = 0;


       while(m.find()) {
         count++;
         System.out.println("So ket noi "+count);
         System.out.println("start(): "+m.start());
         System.out.println("end(): "+m.end());
      }
   }
}

Nó sẽ cho kết quả:

So ket noi 1
start(): 0
end(): 4
So ket noi 2
start(): 5
end(): 9
So ket noi 3
start(): 10
end(): 14
So ket noi 4
start(): 31
end(): 35

Bạn có thể thấy rằng ví dụ này sử dụng các giới hạn từ để bảo đảm rằng chữ cái "c" "a" "t" không đơn thuần là một chuỗi phụ trong một từ dài hơn. Nó cũng cung cấp một số thông tin hữu ích về nơi nào trong chuỗi input xuất hiện sự so khớp.

Phương thức start trả về chỉ mục bắt đầu của dãy phụ được nắm bắt bởi group đã cho trong hoạt động so khớp trước, và phương thức end trả về chỉ mục của ký tự cuối cùng được so khớp, cộng với 1.

Các phương thức matcheslookingAt trong Java

Cả hai phương thức matches và lookingAt so khớp một dãy input với một pattern. Tuy nhiên, sư khác nhau ở đây là phương thức matches yêu cầu toàn bộ dãy input để được so khớp, trong khi phương thức lookingAt thì không.

Cả hai phương thức luôn luôn bắt đầu tại điểm bắt đầu của chuỗi input. Dưới đây là ví dụ giải thích tính năng này:

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegexMatches
{
    private static final String REGEX = "it";
    private static final String INPUT = "itttttttttttttgaphot";
    private static Pattern pattern;
    private static Matcher matcher;


    public static void main( String args[] ){
       pattern = Pattern.compile(REGEX);
       matcher = pattern.matcher(INPUT);


       System.out.println("REGEX hien tai la: "+REGEX);
       System.out.println("INPUT hien tai la: "+INPUT);


       System.out.println("lookingAt(): "+matcher.lookingAt());
       System.out.println("matches(): "+matcher.matches());
   }
}

Nó sẽ cho kết quả sau:

REGEX hien tai la: it
INPUT hien tai la: itttttttttttttgaphot
lookingAt(): true
matches(): false

Các phương thức replaceFirstreplaceAll trong Java

Các phương thức replaceFirst và replaceAll trong Java thay thế text mà so khớp với một Regular Expression đã cho. Như tên của chúng đã cho biết, phương thức replaceFirst thay thế sự xuất hiện so khớp đầu tiên, trong khi phương thức replaceAll thay thế tất cả so khớp.

Ví dụ sau đây giải thích tính năng này

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegexMatches
{
    private static String REGEX = "HaDong";
    private static String INPUT = "HaDong nam o mien nam. " +
                                    "HaDong la thanh pho cua BinhDuong.";
    private static String REPLACE = "BinhDuong";


    public static void main(String[] args) {
       Pattern p = Pattern.compile(REGEX);
       // lay mot doi tuong matcher
       Matcher m = p.matcher(INPUT); 
       INPUT = m.replaceAll(REPLACE);
       System.out.println(INPUT);
   }
}

Nó sẽ cho kết quả sau:

BinhDuong nam o mien nam. BinhDuong la thanh pho cua BinhDuong.

Các phương thức appendReplacementappendTail trong Java

Lớp Matcher cũng cũng cung cấp hai phương thức appendReplacement và appendTail để thay thế văn bản.

Ví dụ sau giải thích tính năng này:

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegexMatches
{
   private static String REGEX = "a*b";
   private static String INPUT = "aabfooaabfooabfoob";
   private static String REPLACE = "-";
   public static void main(String[] args) {
      Pattern p = Pattern.compile(REGEX);
      // lay mot doi tuong matcher
      Matcher m = p.matcher(INPUT);
      StringBuffer sb = new StringBuffer();
      while(m.find()){
         m.appendReplacement(sb,REPLACE);
      }
      m.appendTail(sb);
      System.out.println(sb.toString());
   }
}

Nó sẽ cho kết quả sau:

-foo-foo-foo-

Các phương thức lớp PatternSyntaxException trong Java

Một lớp PatternSyntaxException là một exception chưa được kiểm tra mà chỉ dẫn lỗi cú pháp (syntax error) trong một mẫu Regular Expression. Lớp PatternSyntaxException cung cấp các phương thức sau để giúp bạn xác định cái gì gây ra lỗi.

STTPhương thức và Miêu tả
1public String getDescription()

Thu nhận sự miêu tả về lỗi

2public int getIndex()

Thu nhận chỉ mục của lỗi

3public String getPattern()

Thu nhận mẫu Regular Expression sai sót

4public String getMessage()

Trả về một chuỗi nhiều dòng chứa sự mô tả về syntax error và chỉ mục của nó, mẫu Regular Expression sai sót, và chỉ dẫn có thể nhìn thấy của chỉ mục lỗi trong pattern đó.

Bình luận