一、正则表达式基础语法
1. 元字符速查表
| 元字符 | 说明 | 示例 |
|---|
. | 匹配任意单个字符 | a.c → abc, a&c |
\d | 数字字符 [0-9] | \d\d → 12, 45 |
\D | 非数字字符 [^0-9] | \D\D → ab, #$ |
\w | 单词字符 [a-zA-Z0-9_] | \w+ → hello, A1_ |
\W | 非单词字符 [^\w] | \W → @, 空格 |
\s | 空白字符 [ \t\n\x0B\f\r] | \s+ → ” “, “\n” |
\S | 非空白字符 [^\s] | \S\S → ab, 12 |
^ | 行首 | ^Java → Java开头 |
$ | 行尾 | end$ → 以end结尾 |
2. 量词表达式
| 量词 | 说明 | 示例 |
|---|
* | 0次或多次 | a*b → b, aab |
+ | 1次或多次 | a+b → ab, aaab |
? | 0次或1次 | a?b → b, ab |
{n} | 恰好n次 | a{2} → aa |
{n,} | 至少n次 | a{2,} → aaa |
{n,m} | n到m次 | a{2,4} → aaa |
二、Java正则API核心类
1. Pattern类
// 编译正则表达式(线程安全)
Pattern pattern = Pattern.compile("\\d{3}-\\d{4}");
// 常用方法
Matcher matcher = pattern.matcher("123-4567");
boolean matches = pattern.matches("\\d+", "123"); // 静态快捷方法
2. Matcher类
Matcher matcher = Pattern.compile("\\d+").matcher("a1b23c456");
// 查找方法
while (matcher.find()) {
System.out.println(matcher.group()); // 1, 23, 456
}
// 其他重要方法
boolean matches = matcher.matches(); // 全匹配
boolean lookingAt = matcher.lookingAt(); // 前缀匹配
String replaced = matcher.replaceAll("#"); // a#b#c#
三、字符串操作中的正则
1. String类正则方法
// 分割字符串
String[] parts = "a,b;c".split("[,;]"); // ["a", "b", "c"]
// 替换操作
String result = "a1b2c3".replaceAll("\\d", "#"); // a#b#c#
// 匹配检查
boolean isValid = "123-4567".matches("\\d{3}-\\d{4}"); // true
2. 分组捕获示例
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2023-05-15");
if (m.matches()) {
String year = m.group(1); // 2023
String month = m.group(2); // 05
String day = m.group(3); // 15
}
四、高级匹配技巧
1. 贪婪与懒惰模式
| 模式 | 说明 | 示例 |
|---|
| 贪婪 | 默认模式,尽可能多匹配 | a.*b → “aabab”中匹配整个字符串 |
| 懒惰 | 加?后缀,尽可能少匹配 | a.*?b → “aabab”中匹配”aab”和”ab” |
// 贪婪匹配
Matcher greedy = Pattern.compile("a.*b").matcher("aabab");
greedy.find(); // 匹配整个"aabab"
// 懒惰匹配
Matcher lazy = Pattern.compile("a.*?b").matcher("aabab");
lazy.find(); // 匹配"aab"
lazy.find(); // 匹配"ab"
2. 零宽断言
| 断言类型 | 语法 | 说明 |
|---|
| 正向先行断言 | (?=exp) | 匹配后面是exp的位置 |
| 负向先行断言 | (?!exp) | 匹配后面不是exp的位置 |
| 正向后行断言 | (?<=exp) | 匹配前面是exp的位置 |
| 负向后行断言 | (?<!exp) | 匹配前面不是exp的位置 |
// 提取价格数字
Pattern pricePattern = Pattern.compile("(?<=\\$)\\d+");
Matcher m = pricePattern.matcher("Price: $100, $200");
while (m.find()) {
System.out.println(m.group()); // 100, 200
}
五、常见正则表达式示例
1. 验证类正则
// 电子邮件
String emailRegex = "^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";
// 手机号(中国大陆)
String phoneRegex = "^1[3-9]\\d{9}$";
// 身份证号(18位)
String idCardRegex = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$";
// URL验证
String urlRegex = "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$";
2. 提取类正则
// 提取HTML标签内容
Pattern tagPattern = Pattern.compile("<([a-z]+)>(.*?)</\\1>");
Matcher tagMatcher = tagPattern.matcher("<div>content</div>");
// 提取中文
Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
// 提取IP地址
Pattern ipPattern = Pattern.compile("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b");
六、性能优化与陷阱
1. 预编译模式
// 错误做法:每次调用都编译
void process(String text) {
Pattern.compile(regex).matcher(text).matches(); // 低效
}
// 正确做法:静态预编译
class Validator {
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$");
public static boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
}
2. 常见陷阱
// 陷阱1:忘记转义特殊字符
Pattern.compile("1.2").matcher("123").matches(); // true (点匹配任意字符)
// 陷阱2:过度使用.*
Pattern.compile("A.*B").matcher("AxxxBxxxB").matches(); // 可能意外匹配
// 陷阱3:忽略多行模式
String text = "line1\nline2";
Pattern.compile("^line").matcher(text).find(); // 只匹配第一行
Pattern.compile("^line", Pattern.MULTILINE).matcher(text).find(); // 匹配所有行
七、实战案例
1. 日志解析
String logEntry = "2023-05-15 14:30:22 [ERROR] com.example.Service - NullPointerException";
Pattern logPattern = Pattern.compile(
"(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}) \\[(\\w+)\\] ([\\w.]+) - (.+)"
);
Matcher m = logPattern.matcher(logEntry);
if (m.matches()) {
String date = m.group(1);
String level = m.group(3);
String message = m.group(5);
// 处理日志...
}
2. CSV解析
String csvLine = "John,\"Doe, Jr.\",30,\"New York, NY\"";
Pattern csvPattern = Pattern.compile(
"\"([^\"]*)\"|([^,]+),?"
);
List<String> fields = new ArrayList<>();
Matcher m = csvPattern.matcher(csvLine);
while (m.find()) {
fields.add(m.group(1) != null ? m.group(1) : m.group(2));
}
// fields: ["John", "Doe, Jr.", "30", "New York, NY"]
八、进阶特性
1. 命名捕获组
Pattern p = Pattern.compile(
"(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})"
);
Matcher m = p.matcher("2023-05-15");
if (m.matches()) {
String year = m.group("year"); // 2023
String month = m.group("month"); // 05
String day = m.group("day"); // 15
}
2. 模式标志
| 标志常量 | 说明 |
|---|
| Pattern.CASE_INSENSITIVE | 忽略大小写 |
| Pattern.MULTILINE | 多行模式(^和$匹配行首尾) |
| Pattern.DOTALL | 点号匹配所有字符包括换行符 |
| Pattern.UNICODE_CASE | Unicode感知的大小写忽略 |
// 组合使用多个标志
Pattern.compile("^[a-z]+$",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
);
九、性能测试与对比
1. 不同实现方式性能
| 方法 | 10万次调用耗时(ms) |
|---|
| String.matches() | 1200 |
| 预编译Pattern | 350 |
| 重用Matcher | 280 |
2. 复杂正则优化建议
- 避免回溯爆炸:谨慎使用嵌套量词
(a+)+
- 使用原子组:
(?>...) 防止回溯
- 具体化字符类:用
[a-z] 代替 .*?
- 合理使用锚点:
^ 和 $ 限制匹配范围
通过掌握这些正则表达式技巧,您可以在Java中高效处理各种文本匹配、验证和提取需求。记住复杂的正则表达式虽然强大,但也可能难以维护,在适当情况下考虑拆分为多个简单正则或结合其他字符串操作方法。
暂无评论内容