Java-正则表达式
正则表达式(Regular Expression)是处理字符串的强大工具,Java通过 java.util.regex
包提供支持。字符串的替换和分解是正则表达式的两大核心应用场景。以下是详细讲解:
1. 正则表达式基础
正则表达式是一种描述字符串模式的语法,用于匹配、查找、替换或分割字符串。
1.1 常用元字符
元字符 | 说明 | 示例 | ||
---|---|---|---|---|
. | 匹配任意字符(除换行符) | a.c → "abc", "a c" | ||
\d | 匹配数字(等价于 [0-9] ) | \d+ → "123" | ||
\w | 匹配单词字符(字母、数字、下划线) | \w+ → "user_1" | ||
\s | 匹配空白字符(空格、制表符等) | a\sb → "a b" | ||
^ | 匹配字符串开头 | ^Java → "Java is..." | ||
$ | 匹配字符串结尾 | end$ → "...end" | ||
[] | 匹配括号内的任意字符 | [aeiou] → "a", "e" | ||
` | ` | 或操作 | `cat | dog` → "cat" 或 "dog" |
1.2 量词
量词 | 说明 | 示例 |
---|---|---|
* | 0次或多次 | a* → "", "a", "aa" |
+ | 1次或多次 | \d+ → "1", "123" |
? | 0次或1次 | colou?r → "color", "colour" |
{n} | 恰好n次 | a{2} → "aa" |
{n,} | 至少n次 | a{2,} → "aa", "aaa" |
2. 字符串的替换
2.1 String.replaceAll()
和 String.replaceFirst()
-
replaceAll(String regex, String replacement)
:替换所有匹配的子串。 -
replaceFirst(String regex, String replacement)
:替换第一个匹配的子串。
示例:
String text = "Java 8, Java 11, Java 17";
String replacedAll = text.replaceAll("Java \\d+", "JDK"); // "JDK, JDK, JDK"
String replacedFirst = text.replaceFirst("Java \\d+", "JDK"); // "JDK, Java 11, Java 17"
2.2 使用捕获组
用 ()
定义捕获组,通过 $n
引用(n
为组号)。
示例:交换单词顺序
String text = "Hello World";
String swapped = text.replaceAll("(\\w+) (\\w+)", "$2 $1"); // "World Hello"
3. 字符串的分解(分割)
3.1 String.split()
根据正则表达式分割字符串,返回数组。
示例:
String csv = "A,B,C,D";
String[] parts = csv.split(","); // ["A", "B", "C", "D"]// 复杂分割:按多个分隔符(逗号或分号)
String data = "A,B;C;D";
String[] items = data.split("[,;]"); // ["A", "B", "C", "D"]
3.2 处理空字符串
默认会删除末尾的空字符串,可通过限制参数保留:
String text = "A,B,,C,";
String[] parts1 = text.split(","); // ["A", "B", "", "C"]
String[] parts2 = text.split(",", -1); // ["A", "B", "", "C", ""]
4. 正则表达式的高级使用
4.1 Pattern
和 Matcher
类
用于复杂的匹配和提取操作。
示例:提取所有数字
import java.util.regex.*;String text = "Prices: $10, $20, $30";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);while (matcher.find()) {System.out.println(matcher.group()); // 输出:10, 20, 30
}
4.2 分组提取
通过捕获组提取特定部分。
示例:提取日期中的年、月、日
String date = "2023-10-05";
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(date);if (matcher.matches()) {String year = matcher.group(1); // "2023"String month = matcher.group(2); // "10"String day = matcher.group(3); // "05"
}
5. 常见应用场景
5.1 校验输入格式
// 校验邮箱格式
String email = "user@example.com";
boolean isValid = email.matches("\\w+@\\w+\\.\\w+"); // true
5.2 清理字符串
// 移除所有非字母字符
String dirty = "A1B2C3!";
String clean = dirty.replaceAll("[^A-Za-z]", ""); // "ABC"
5.3 复杂文本解析
// 从HTML中提取所有链接
String html = "<a href='https://example.com'>Link</a>";
Pattern linkPattern = Pattern.compile("href='(.*?)'");
Matcher linkMatcher = linkPattern.matcher(html);while (linkMatcher.find()) {System.out.println(linkMatcher.group(1)); // "https://example.com"
}
6. 性能优化建议
-
预编译正则表达式:
多次使用时,先编译Pattern
对象以提高性能。Pattern pattern = Pattern.compile("\\d+"); // 预编译 Matcher matcher = pattern.matcher(text);
-
避免贪婪量词:
使用*?
或+?
进行非贪婪匹配,避免过度匹配。String text = "<div>Content</div><div>More</div>"; text.replaceAll("<div>(.*?)</div>", ""); // 非贪婪匹配
-
选择简单分隔符:
如果只需按固定字符分割,优先用StringTokenizer
或String.split()
的简单模式。
7. 总结
操作 | 方法/类 | 适用场景 |
---|---|---|
替换 | replaceAll() , replaceFirst() | 批量替换或单次替换 |
分割 | split() | 按正则表达式分解字符串 |
复杂匹配 | Pattern 和 Matcher | 提取、校验或多次匹配 |
高效处理 | 预编译 Pattern | 频繁使用同一正则时提升性能 |
关键点:
-
正则表达式是字符串处理的瑞士军刀,但需注意性能。
-
简单场景用
String
类方法,复杂场景用Pattern
/Matcher
。 -
始终测试正则表达式(可用在线工具如 Regex101)。