Regex

Duy Văn | 12/03/2025


Regex là một công cụ rất mạnh dành cho việc xử lý các chuỗi dài với các tác vụ tìm kiếm và thay thế từ

Java không có built-in regex mà sẽ sử dụng package java.util.regex với 3 class chính:

  • Pattern class - định nghĩa pattern để tìm kiếm
  • Matcher class - thực hiện tìm kiếm
  • PatternSyntaxException class - class Exception khi lỗi syntax trong pattern

Việc triển khai regex sẽ luôn cần sử dụng cả 2 class là Pattern và Matcher


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

Ví dụ cho một string “Hello World” và chúng ta muốn tìm kiếm từ “Hello” trong string đó


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

public class Main {
  public static void main(String[] args) {
    String text = "Hello World";
    String pattern = "Hello";
    Pattern p = Pattern.compile(pattern);
    Matcher m = p.matcher(text);
    System.out.println(m.find());
  }
}

Đầu tiên, Pattern.compile() sẽ tạo ra pattern dùng để tìm kiếm, chúng ta có thể để như trên, tức là tìm chính xác “Hello”, hoặc Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); để tìm kiếm không phân biệt chữ hoa chữ thường

matcher() method của class Match sẽ tìm kiếm pattern trong string, nó trả ra một object Matcher chứa thuộc tính liên quan

find() method của object Matcher trả ra boolean rằng pattern có được tìm thấy hay không

Để lấy giá trị tìm được, chúng ta sử dụng group() method của object Matcher


import java.util.regex.Matcher;

public class Main {
  public static void main(String[] args) {
    String text = "Hello World";
    String pattern = "Hello";
    Pattern p = Pattern.compile(pattern);
    Matcher m = p.matcher(text);
    if (m.find()) {
      System.out.println(m.group());
    }
  }
}

Bắt buộc phải gọi find() trước khi gọi group() nếu không sẽ báo lỗi, vì find() ngoại trừ trả ra true hay false, bản chất của nó chính là thực hiện tìm kiếm, không tìm kiếm thì lấy đâu ra kết quả?

Flags của compile()

Khi sử dụng compile() để tạo pattern, có 3 flag chính để xác định cách pattern sẽ tìm kiếm:

  • Pattern.CASE_INSENSITIVE - không phân biệt chữ hoa chữ thường
  • Pattern.LITERAL - các ký tự đặc biệt trong pattern sẽ được coi là ký tự bình thường
  • Pattern.UNICODE_CASE - không phân biệt chữ hoa chữ thường khi sử dụng cùng với Pattern.CASE_INSENSITIVE

Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);


Pattern p = Pattern.compile(pattern, Pattern.LITERAL);


Pattern p = Pattern.compile(pattern
  , Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);

Pattern thường gặp

Để sử dụng vào param đầu tiên của compile(), chúng ta cần phải biết một số pattern thường gặp:

  • [abc] - a, b hoặc c - tìm kiếm các ký tự trong dấu ngoặc vuông
  • [^abc] - không phải a, b hoặc c - tìm kiếm các ký tự không nằm trong dấu ngoặc vuông
  • [a-z] - a đến z
  • [A-Z] - A đến Z
  • [0-9] - 0 đến 9
  • [a-zA-Z] - a đến z hoặc A đến Z

Metacharacters

Các metacharacters là các ký tự đặc biệt trong regex, chúng ta cần phải escape chúng nếu muốn tìm kiếm chính xác chúng:

  • . - tìm chỉ 1 lần xuất hiện bất kỳ ký tự nào
  • | - tìm kiếm 1 trong các pattern tách bởi dấu | - ví dụ a|b sẽ tìm kiếm a hoặc b
  • ^ - tìm kiếm từ đầu chuỗi
  • $ - tìm kiếm từ cuối chuỗi
  • \d - tìm kiếm số
  • \s - tìm kiếm khoảng trắng
  • \b - tìm kiếm từ đầu hoặc cuối từ - ví dụ \bWORD sẽ tìm được cả WORDS và WORD, còn WORD\b sẽ tìm được chỉ WORD
  • \uxxxx - tìm kiếm ký tự unicode- ví dụ \u0041 sẽ tìm kiếm ký tự A

Quantifiers

Quantifiers là các ký tự để xác định số lần xuất hiện của pattern:

  • * - 0 hoặc nhiều lần - ví dụ a* sẽ tìm được a, aa, aaa,…
  • + - 1 hoặc nhiều lần - ví dụ a+ sẽ tìm được a, aa, aaa,…
  • ? - 0 hoặc 1 lần - ví dụ a? sẽ tìm được a hoặc không tìm được gì
  • {n} - chính xác n lần - ví dụ a{2} sẽ tìm được aa
  • {n,} - ít nhất n lần - ví dụ a{2,} sẽ tìm được aa, aaa,…
  • {n,m} - từ n đến m lần - ví dụ a{2,4} sẽ tìm được aa, aaa, aaaa