一、Java 正则表达式核心类

Java 通过 java.util.regex 包中的两个核心类处理正则表达式:

  1. Pattern:编译后的正则表达式对象(不可变,线程安全)。
  2. Matcher:用于对输入字符串进行匹配和操作。

二、基本语法与元字符

1. 常用元字符

元字符 说明
. 匹配任意字符(除换行符)
\d 数字 [0-9]
\D 非数字 [^0-9]
\w 单词字符 [a-zA-Z0-9_]
\W 非单词字符
\s 空白字符(空格、制表符等)
\S 非空白字符
^ 字符串开始
$ 字符串结束

2. 量词

量词 说明
* 0次或多次
+ 1次或多次
? 0次或1次
{n} 恰好n次
{n,} 至少n次
{n,m} 至少n次,至多m次

3. 分组与捕获

语法 说明
(exp) 捕获分组
(?:exp) 非捕获分组
(?<name>exp) 命名分组(Java 7+)

4. 边界与断言

语法 说明
\b 单词边界
(?=exp) 正向肯定前瞻
(?!exp) 正向否定前瞻
(?<=exp) 正向肯定后顾
(?<!exp) 正向否定后顾

三、Java 中的正则表达式用法

1. 字符串方法快速匹配

1
2
3
4
String str = "Hello123";
boolean isMatch = str.matches("^[A-Za-z]+\\d+$"); // 匹配字母+数字
String replaced = str.replaceAll("\\d", "*"); // 替换数字为*
String[] parts = str.split("\\d+"); // 按数字分割

2. 使用 PatternMatcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.regex.*;

// 1. 编译正则表达式
Pattern pattern = Pattern.compile("\\b\\w+\\b");

// 2. 创建 Matcher 对象
Matcher matcher = pattern.matcher("Hello World");

// 3. 查找匹配
while (matcher.find()) {
System.out.println("找到: " + matcher.group());
}

// 4. 完整匹配验证
boolean isFullMatch = matcher.matches();

// 5. 替换操作
String result = matcher.replaceAll("Java");

四、高级功能示例

1. 命名分组(Java 7+)

1
2
3
4
5
6
7
String regex = "(?<year>\\d{4})-(?<month>\\d{2})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher("2023-10");
if (matcher.find()) {
String year = matcher.group("year"); // 2023
String month = matcher.group("month"); // 10
}

2. 非贪婪匹配

1
2
3
4
5
// 默认贪婪匹配:匹配最长字符串
Pattern.compile("a.*b").matcher("aababb").find(); // 匹配 "aababb"

// 非贪婪匹配:匹配最短字符串
Pattern.compile("a.*?b").matcher("aababb").find(); // 匹配 "aab"

3. 反向引用

1
2
3
4
5
// 匹配重复单词(如 "the the")
String regex = "\\b(\\w+)\\b\\s+\\1\\b";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher("the the");
boolean isMatch = matcher.find(); // true

五、常见用例

案例 1:验证手机号(中国)

需求:匹配以 13/14/15/17/18/19 开头的 11 位手机号。

1
2
3
	String regex = "^1[345789]\\d{9}$";
String phone = "13812345678";
boolean isValid = phone.matches(regex); // true

解释

  • ^1:以 1 开头。
  • [345789]:第二位是 3/4/5/7/8/9 中的一个。
  • \\d{9}$:后接 9 位数字,总长度 11 位。

案例 2:提取 HTML 标签中的内容

需求:提取 <div> 标签内的文本内容。

1
2
3
4
5
6
String html = "<div class='header'>Hello World</div>";
Pattern pattern = Pattern.compile("<div.*?>(.*?)</div>");
Matcher matcher = pattern.matcher(html);
if (matcher.find()) {
String content = matcher.group(1); // "Hello World"
}

解释

  • <div.*?>:匹配 <div 开头,.*? 非贪婪匹配任意字符直到 >
  • (.*?):捕获组,非贪婪匹配标签内容。
  • </div>:匹配闭合标签。

案例 3:密码强度验证

需求:密码必须包含大小写字母、数字和特殊符号,长度 8-20。

1
2
3
String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,20}$";
String password = "Passw0rd!";
boolean isStrong = password.matches(regex); // true

解释

  • (?=.*[a-z]):正向肯定前瞻,确保至少一个小写字母。
  • (?=.*[A-Z]):至少一个大写字母。
  • (?=.*\\d):至少一个数字。
  • (?=.*[@$!%*?&]):至少一个特殊符号。
  • [A-Za-z\\d@$!%*?&]{8,20}:允许的字符范围,长度 8-20。

案例 4:提取 CSV 文件中的字段

需求:处理 CSV 行,支持字段含逗号和引号。

1
2
3
4
5
6
7
8
String csvLine = "John,\"Doe, Jr.\",30";
Pattern pattern = Pattern.compile("(\"[^\"]*\"|[^,]+)");
Matcher matcher = pattern.matcher(csvLine);
List<String> fields = new ArrayList<>();
while (matcher.find()) {
String field = matcher.group(1).replaceAll("\"", "");
fields.add(field); // ["John", "Doe, Jr.", "30"]
}

解释

  • (\"[^\"]*\"|[^,]+):匹配两种模式:
    • \"[^\"]*\":引号内的内容(如 "Doe, Jr.")。
    • [^,]+:不含逗号的普通字段。

案例 5:验证 IPv4 地址

需求:验证合法的 IPv4 地址(如 192.168.1.1)。

1
2
3
String regex = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
String ip = "192.168.1.1";
boolean isValid = ip.matches(regex); // true

解释

  • 25[0-5]:匹配 250-255。
  • 2[0-4]\\d:匹配 200-249。
  • [01]?\\d\\d?:匹配 0-199。
  • 重复 4 次,用 \\. 分隔。

六、性能优化

  1. 预编译正则表达式:重用 Pattern 对象,避免重复编译。
  2. 避免贪婪量词滥用:使用非贪婪量词(*?+?)减少回溯。
  3. 简化复杂表达式:优先使用字符类(如 \d 代替 [0-9])。

七、常见问题

1. 转义问题

Java 字符串中的反斜杠 \ 需转义为 \\

1
2
// 匹配一个数字:正则表达式是 \d,Java 中需写成 "\\d"
Pattern.compile("\\d");

2. matches() 方法

matcher.matches() 会尝试匹配整个字符串,等同于在正则表达式前后加 ^$

3. 区分大小写

默认区分大小写,通过 Pattern.CASE_INSENSITIVE 标志忽略大小写:

1
Pattern.compile("hello", Pattern.CASE_INSENSITIVE);