正则表达式深入详细解析
学习目标:
-
掌握正则表达式核心语法与元字符
-
理解分组、捕获、零宽断言等高级特性
-
能够编写复杂正则表达式解决实际问题
-
使用Java API高效处理正则匹配与替换
一、课程引入
1.1 正则表达式的应用场景
-
数据验证:邮箱、手机号、密码强度
-
文本处理:日志解析、数据提取、格式转换
-
开发工具:IDE中的查找替换、日志分析工具
1.2 正则表达式在Java中的实现
-
java.util.regex包:-
Pattern:编译正则表达式 -
Matcher:执行匹配操作
-
二、正则表达式基础
2.1 基本语法与元字符
| 元字符 | 说明 | 示例 |
|---|---|---|
. | 匹配任意字符(除换行符) | a.c → "abc"、"a2c" |
\d | 匹配数字(等价于[0-9]) | \d{3} → "123" |
\w | 匹配单词字符([a-zA-Z0-9_]) | \w+ → "user123" |
\s | 匹配空白字符(空格、制表符等) | \s+ → " " |
^ / $ | 匹配字符串开始/结束 | ^Hello → 以Hello开头 |
案例1:简单匹配
String text = "订单号:ORD123456,金额:¥500.00";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("找到数字:" + matcher.group());
}
// 输出:ORD123456、500、00
三、分组与捕获
3.1 分组语法
| 语法 | 说明 |
|---|---|
(pattern) | 捕获分组 |
(?:pattern) | 非捕获分组(不保存匹配结果) |
(?<name>pattern) | 命名分组(Java 7+) |
案例2:提取日期各部分
String date = "2023-10-01";
Pattern pattern = Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
Matcher matcher = pattern.matcher(date);
if (matcher.find()) {
System.out.println("年:" + matcher.group("year")); // 2023
System.out.println("月:" + matcher.group("month")); // 10
System.out.println("日:" + matcher.group("day")); // 01
}
3.2 反向引用
// 查找重复单词
String text = "the the cat sat on the the mat";
Pattern pattern = Pattern.compile("\\b(\\w+)\\s+\\1\\b");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("重复单词:" + matcher.group()); // "the the"
}
四、零宽断言与贪婪模式
4.1 零宽断言(Lookaround)
| 语法 | 说明 |
|---|---|
(?=pattern) | 正向肯定断言(后面跟着pattern) |
(?!pattern) | 正向否定断言(后面不跟pattern) |
(?<=pattern) | 反向肯定断言(前面是pattern) |
(?<!pattern) | 反向否定断言(前面不是pattern) |
案例3:密码强度校验
// 要求:至少8位,包含大小写字母和数字
String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$";
System.out.println("Passw0rd".matches(regex)); // true
System.out.println("password".matches(regex)); // false
4.2 贪婪与懒惰模式
| 量词 | 说明 | 示例(字符串:<div>content</div>) |
|---|---|---|
* | 贪婪匹配 | <.*> → 匹配整个字符串 |
*? | 懒惰匹配 | <.*?> → 匹配<div>和</div> |
案例4:提取HTML标签内容
String html = "<div>Hello</div><p>World</p>";
Pattern pattern = Pattern.compile("<div>(.*?)</div>");
Matcher matcher = pattern.matcher(html);
if (matcher.find()) {
System.out.println("内容:" + matcher.group(1)); // Hello
}
五、综合应用案例
String log = "192.168.1.1 - - [01/Oct/2023:10:20:30 +0800] \"GET /api/user?id=123 HTTP/1.1\" 200 1024";
String regex = "(?<ip>\\d+\\.\\d+\\.\\d+\\.\\d+).*?\"(?<method>\\w+) (?<url>[^\"]+)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(log);
if (matcher.find()) {
System.out.println("IP:" + matcher.group("ip")); // 192.168.1.1
System.out.println("方法:" + matcher.group("method")); // GET
System.out.println("URL:" + matcher.group("url")); // /api/user?id=123
}
5.2 案例6:SQL语句格式化
String sql = "SELECT id,name,age FROM users WHERE age>20 AND status=1;";
String formatted = sql.replaceAll("(?i)\\b(SELECT|FROM|WHERE|AND)\\b", "\n$1 ")
.replaceAll(",", ",\n ");
System.out.println(formatted);
/* 输出:
SELECT id, name, age FROM users WHERE age>20 AND status=1;
*/
六、常见问题与最佳实践
6.1 常见错误
-
错误1:未转义特殊字符
// 错误:.是元字符,需转义 "192.168.1.1".matches("\\d+.\\d+.\\d+.\\d+"); // false // 正确: "192.168.1.1".matches("\\d+\\.\\d+\\.\\d+\\.\\d+"); // true -
错误2:过度复杂的正则
// 错误:尝试用正则解析HTML(应使用专用解析器) String htmlRegex = "<div>.*</div>";
6.2 最佳实践
-
优先可读性:复杂正则添加注释(
(?x)模式) -
测试工具:使用Regex101在线测试
-
性能优化:预编译
Pattern对象,避免重复编译
七、总结与练习
7.1 总结
-
核心语法:元字符、分组、零宽断言
-
性能陷阱:贪婪匹配、回溯爆炸
-
Java API:
Pattern、Matcher、split、replaceAll
7.2 课后任务
-
编写正则表达式验证中国大陆手机号(1开头,11位数字)
-
从JSON字符串中提取所有键名(如
{"name":"John", "age":30}→ ["name", "age"]) -
预习下一节课:Java网络编程基础
7.3 扩展挑战
-
实现一个简单的日志分析工具,统计各IP的访问次数
9330

被折叠的 条评论
为什么被折叠?



