Java 正则表达式
1. 概述
正则表达式(Regular Expression,简称 regex)是一种用于匹配字符串的模式描述语言。在 Java 中,正则表达式通过 java.util.regex 包提供支持,主要包括以下三个核心类:
- Pattern:表示编译后的正则表达式。
- Matcher:用于对输入字符串执行匹配操作。
- PatternSyntaxException:当正则表达式语法错误时抛出的异常。
Java 的正则表达式遵循 Perl 5 兼容的语法规范,功能强大且灵活,适用于文本验证、提取、替换和分割等场景。
2. 基本使用流程
2.1 编译正则表达式
java
Pattern pattern = Pattern.compile("your-regex");
注意 :
Pattern对象是线程安全且不可变的,可被多个线程共享以提高性能。
2.2 创建匹配器
java
Matcher matcher = pattern.matcher("input string");
2.3 执行匹配操作
常用方法包括:
| 方法 | 描述 |
|---|---|
matches() |
判断整个字符串是否匹配正则表达式 |
find() |
查找下一个匹配子串(可用于多次调用) |
lookingAt() |
判断字符串开头是否匹配 |
replaceAll(String replacement) |
替换所有匹配项 |
replaceFirst(String replacement) |
替换第一个匹配项 |
group(int group) |
获取指定捕获组的内容 |
3. 正则表达式语法详解
3.1 字符类
| 表达式 | 含义 |
|---|---|
[abc] |
匹配 a、b 或 c |
[^abc] |
不匹配 a、b、c |
[a-z] |
匹配小写字母 a 到 z |
[0-9] |
等价于 \d |
\w |
单词字符(等价于 [a-zA-Z_0-9]) |
\W |
非单词字符 |
\s |
空白字符(空格、制表符、换行等) |
\S |
非空白字符 |
\d |
数字(等价于 [0-9]) |
\D |
非数字 |
3.2 量词(Quantifiers)
| 表达式 | 含义 |
|---|---|
X? |
X 出现 0 次或 1 次(贪婪) |
X* |
X 出现 0 次或多次 |
X+ |
X 出现 1 次或多次 |
X{n} |
X 恰好出现 n 次 |
X{n,} |
X 至少出现 n 次 |
X{n,m} |
X 出现 n 到 m 次 |
贪婪 vs 惰性 :默认为贪婪匹配。在量词后加
?可变为惰性(如.*?)。
3.3 边界匹配器
| 表达式 | 含义 |
|---|---|
^ |
行的开始 |
$ |
行的结束 |
\b |
单词边界 |
\B |
非单词边界 |
\A |
输入的开始 |
\Z |
输入的结束(忽略最后的换行符) |
\z |
输入的绝对结束 |
3.4 分组与捕获
使用圆括号 () 创建捕获组:
java
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2026-01-22");
if (m.matches()) {
System.out.println(m.group(1)); // "2026"
System.out.println(m.group(2)); // "01"
System.out.println(m.group(3)); // "22"
}
group(0):整个匹配内容。group(n):第 n 个捕获组(从 1 开始计数)。- 非捕获组:使用
(?:...),例如(?:\d{3})不保存匹配结果。
3.5 零宽断言(Lookaround)
| 表达式 | 含义 |
|---|---|
(?=X) |
正向先行断言(后面必须是 X) |
(?!X) |
负向先行断言(后面不能是 X) |
(?<=X) |
正向后行断言(前面必须是 X) |
(?<!X) |
负向后行断言(前面不能是 X) |
注意 :Java 支持固定长度的后行断言(如
(?<=abc)),但不支持可变长度(如(?<=a+))。
4. 常用示例
4.1 验证邮箱
java
String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
boolean isValid = email.matches(emailRegex);
4.2 提取所有数字
java
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("Price: $123 and ID: 4567");
while (m.find()) {
System.out.println(m.group()); // 输出 123, 4567
}
4.3 替换敏感词
java
String text = "This is a bad word.";
String result = text.replaceAll("(bad|ugly)", "***");
// 结果: "This is a *** word."
4.4 分割字符串(保留分隔符)
java
String[] parts = "a,b;c".split("[,;]");
// ["a", "b", "c"]
5. 性能优化建议
-
预编译 Pattern :避免在循环中重复调用
Pattern.compile()。javaprivate static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"); -
避免回溯爆炸 :谨慎使用嵌套量词(如
(a+)+),可能导致指数级回溯。 -
使用
String.matches()谨慎 :该方法隐式添加了^...$,仅适用于全字符串匹配。 -
考虑使用
java.util.function.Predicate封装验证逻辑:javaPredicate<String> isEmail = EMAIL_PATTERN.asPredicate();
6. 异常处理
正则表达式语法错误会抛出 PatternSyntaxException:
java
try {
Pattern.compile("[");
} catch (PatternSyntaxException e) {
System.err.println("Invalid regex: " + e.getDescription());
}
7. 与其他工具对比
| 特性 | Java Regex | JavaScript | Python (re) |
|---|---|---|---|
| Unicode 支持 | 完整(UTF-16) | 有限 | 完整 |
| 后行断言 | 固定长度 | ES2018+ 支持 | 支持(固定/可变) |
| 命名捕获组 | Java 7+ 支持 (?<name>...) |
ES2018+ | 支持 |
| 多行模式 | Pattern.MULTILINE |
/m 标志 |
re.MULTILINE |
8. 高级特性(Java 7+)
8.1 呓名捕获组
java
Pattern p = Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})");
Matcher m = p.matcher("2026-01");
if (m.matches()) {
System.out.println(m.group("year")); // "2026"
System.out.println(m.group("month")); // "01"
}
8.2 标志(Flags)
可通过 Pattern.compile(regex, flags) 设置:
| 标志 | 作用 |
|---|---|
Pattern.CASE_INSENSITIVE |
忽略大小写 |
Pattern.MULTILINE |
^ 和 $ 匹配每行 |
Pattern.DOTALL |
. 匹配包括换行符 |
Pattern.UNICODE_CASE |
与 CASE_INSENSITIVE 联用支持 Unicode |
也可在正则内部使用内联标志:(?i) 表示忽略大小写。
9. 总结
Java 正则表达式是处理字符串的强大工具,适用于验证、解析、清洗等多种场景。合理使用 Pattern 和 Matcher 类,结合对正则语法的深入理解,可以高效解决复杂的文本处理问题。同时需注意性能陷阱和安全性(如 ReDoS 攻击),在生产环境中应进行充分测试。
参考文献: