Java 正規表達式 (Regular Expressions)
正規表達式用來匹配和處理字串模式。
基本使用
String 的正規方法
String str = "Hello World";
// matches:完全匹配
str.matches("Hello.*"); // true
// replaceAll:取代
str.replaceAll("\\s+", "-"); // "Hello-World"
// replaceFirst:取代第一個
str.replaceFirst("o", "0"); // "Hell0 World"
// split:分割
"a,b,c".split(","); // ["a", "b", "c"]
Pattern 和 Matcher
import java.util.regex.*;
String text = "The cat sat on the mat";
String regex = "\\b\\w{3}\\b"; // 3 個字母的單字
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(matcher.group()); // The, cat, sat, the, mat
}
常用語法
字元類別
| 語法 | 說明 |
|---|
. | 任意字元 |
\d | 數字 [0-9] |
\D | 非數字 |
\w | 單字字元 [a-zA-Z0-9_] |
\W | 非單字字元 |
\s | 空白字元 |
\S | 非空白字元 |
[abc] | a, b, 或 c |
[^abc] | 非 a, b, c |
[a-z] | a 到 z |
量詞
| 語法 | 說明 |
|---|
* | 0 或多個 |
+ | 1 或多個 |
? | 0 或 1 個 |
{n} | 剛好 n 個 |
{n,} | 至少 n 個 |
{n,m} | n 到 m 個 |
錨點
群組
| 語法 | 說明 |
|---|
(...) | 捕獲群組 |
(?:...) | 非捕獲群組 |
\1 | 反向參照 |
Pattern 方法
// 編譯
Pattern pattern = Pattern.compile("\\d+");
// 帶旗標編譯
Pattern patternCI = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
// 快速匹配
Pattern.matches("\\d+", "12345"); // true
// 分割
String[] parts = pattern.split("a1b2c3"); // ["a", "b", "c"]
旗標
Pattern.CASE_INSENSITIVE // 忽略大小寫
Pattern.MULTILINE // 多行模式
Pattern.DOTALL // . 匹配換行
Pattern.UNICODE_CASE // Unicode 大小寫
Matcher 方法
Matcher matcher = pattern.matcher(text);
matcher.matches(); // 完全匹配
matcher.find(); // 尋找下一個
matcher.group(); // 取得匹配的字串
matcher.group(1); // 取得群組 1
matcher.start(); // 匹配的開始位置
matcher.end(); // 匹配的結束位置
matcher.reset(); // 重設
實際應用
驗證 Email
public static boolean isValidEmail(String email) {
String regex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
return email.matches(regex);
}
isValidEmail("user@example.com"); // true
isValidEmail("invalid"); // false
驗證電話號碼
public static boolean isValidPhone(String phone) {
String regex = "^09\\d{8}$"; // 台灣手機
return phone.matches(regex);
}
提取數字
String text = "價格是 100 元,數量 5 個";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
List<Integer> numbers = new ArrayList<>();
while (matcher.find()) {
numbers.add(Integer.parseInt(matcher.group()));
}
// [100, 5]
提取 URL
String text = "訪問 https://example.com 或 http://test.org";
String regex = "https?://[\\w.-]+(?:/[\\w.-]*)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(matcher.group());
}
// https://example.com
// http://test.org
取代
// 隱藏電話號碼
String phone = "0912345678";
String masked = phone.replaceAll("(\\d{4})\\d{4}(\\d{2})", "$1****$2");
// "0912****78"
// 移除 HTML 標籤
String html = "<p>Hello <b>World</b></p>";
String text = html.replaceAll("<[^>]+>", "");
// "Hello World"
使用群組
String log = "2024-12-10 14:30:45 INFO User logged in";
String regex = "(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (\\w+) (.+)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(log);
if (matcher.matches()) {
String date = matcher.group(1); // 2024-12-10
String time = matcher.group(2); // 14:30:45
String level = matcher.group(3); // INFO
String message = matcher.group(4); // User logged in
}
命名群組 (Java 7+)
String regex = "(?<date>\\d{4}-\\d{2}-\\d{2}) (?<time>\\d{2}:\\d{2}:\\d{2})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher("2024-12-10 14:30:45");
if (matcher.matches()) {
String date = matcher.group("date"); // 2024-12-10
String time = matcher.group("time"); // 14:30:45
}
注意事項
跳脫字元
在 Java 字串中,\ 需要跳脫:
// 匹配數字
String regex = "\\d+"; // Java 字串中用 \\d
// 匹配反斜線
String regex2 = "\\\\"; // 匹配一個 \
效能
重複使用的正規表達式應該預先編譯:
// 不好:每次都編譯
for (String s : strings) {
if (s.matches("\\d+")) { }
}
// 好:預先編譯
Pattern pattern = Pattern.compile("\\d+");
for (String s : strings) {
if (pattern.matcher(s).matches()) { }
}