在軟體開發中,字串比對、搜尋、替換、驗證是家常便飯。若純靠手寫邏輯處理複雜字串模式,不僅程式碼冗長難維護,更極易出錯。Java 自 JDK 1.4 引入 java.util.regex 套件,提供強大、標準化的正則引擎,讓開發者能以宣告式語法輕鬆解決棘手的字串處理問題。
| 符號 | 說明 | 等價表示 |
|---|---|---|
| \t | 定位符 | \u0009 |
| \n | 換行 | \u000A |
| \d | 數字 | [0-9] |
| \D | 非數字 | [^0-9] |
| \s | 空白字元 | [\t\n\x0B\f\r] |
| \w | 單字字元 | [a-zA-Z_0-9] |
| \b | 單字邊界 | - |
^:字串開頭(多行模式下為行首)$:字串結尾(多行模式下為行尾).:任意單一字元(預設不含換行)*:零次或多次+:一次或多次?:零次或一次{n}:恰好 n 次{n,}:至少 n 次{n,m}:n 到 m 次[abc] // a 或 b 或 c
[a-z] // 小寫字母
[^abc] // 非 a、b、c
(abc) // 捕獲群組
(?:abc) // 非捕獲群組
a|b // a 或 b
Pattern.compile(regex, flags) 常用旗標:
| 旗標 | 常數 | 效果 |
|---|---|---|
| i | CASE_INSENSITIVE | 忽略大小寫(預設僅 ASCII) |
| u | UNICODE_CASE | 配合 i 旗標支援 Unicode 大小寫 |
| m | MULTILINE | ^/$ 匹配行首尾 |
| s | DOTALL | . 匹配含換行在內任意字元 |
| x | COMMENTS | 忽略模式中的空白與註解 |
| d | UNIX_LINES | 僅 \n 視為行結束 |
Pattern p = Pattern.compile("^Java.*");
Matcher m = p.matcher("Java不是人");
System.out.println(m.matches()); // true
String[] parts = Pattern.compile("[,|\\s]+")
.split("Java Hello World Java,Hello,,World|Sun");
// 結果: [Java, Hello, World, Java, Hello, World, Sun]
String input = "正則表達式 Hello, 正則表達式 World";
Pattern p = Pattern.compile("正則表達式");
Matcher m = p.matcher(input);
System.out.println(m.replaceFirst("Java")); // 替換首次
System.out.println(m.replaceAll("Java")); // 替換全部
// 進階:StringBuffer 逐個替換
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "Java");
}
m.appendTail(sb);
System.out.println(sb);
String email = "user@example.com.cn";
Pattern p = Pattern.compile("[\\w.-]+@([\\w-]+\\.)+[\\w-]+", Pattern.CASE_INSENSITIVE);
System.out.println(p.matcher(email).matches()); // true
String html = "首頁";
String text = Pattern.compile("<.+?>", Pattern.DOTALL)
.matcher(html)
.replaceAll("");
// 結果: 首頁
Pattern p = Pattern.compile("href=\"(.+?)\"");
Matcher m = p.matcher("首頁");
if (m.find()) System.out.println(m.group(1)); // index.html
Pattern p = Pattern.compile("(https?://)[\\w./:-]+");
Matcher m = p.matcher("訪問 https://example.com/path?q=1 吧");
while (m.find()) System.out.println(m.group()); // https://example.com/path?q=1
String template = "Java發展史: {0}年-{1}年";
String[][] params = {{"\\{0\\}", "1995"}, {"\\{1\\}", "2007"}};
String result = template;
for (String[] kv : params) {
result = Pattern.compile(kv[0]).matcher(result).replaceAll(kv[1]);
}
System.out.println(result); // Java發展史: 1995年-2007年
public class FileFinder {
private final List<File> files = new ArrayList<>();
public void find(String dirPath, String regex) {
File dir = new File(dirPath);
File[] matched = dir.listFiles(f -> Pattern.matches(regex, f.getName()));
if (matched != null) Collections.addAll(files, matched);
}
public void print() {
files.forEach(f -> System.out.println(f.getPath()));
}
public static void main(String[] args) {
new FileFinder().find("C:/", "[A-Za-z.]+").print();
}
}
Pattern 為執行緒安全,重複使用可避免重複編譯開銷。(?:...) 減少記憶體佔用。(a+)+ 易導致災難性回溯。[a-z] 比 . 快且精確。^pattern$ 可快速失敗非目標字串。正則表達式是字串處理的瑞士刀,Java 的 java.util.regex 提供完整、高效能的實作。掌握核心語法、旗標與 Pattern/Matcher API,配合預編譯與防災難性回溯技巧,即能優雅解決 90% 以上的字串比對需求。建議收藏本文語法表,實戰中查閱最效率。