🌟 前言:正则表达式的力量
正则表达式(Regex)是代码世界中的"瑞士军刀",能在文本处理、数据清洗、表单验证等场景中创造奇迹。2025年Java生态的最新优化让正则性能提升300%,本文将用代码示例+可视化图表+实战案例带你彻底掌握。
📜 目录
🔥 第1章 正则表达式核心语法(表格速查)
1.1 元字符大全(2025最新版)
语法 |
名称/类别 |
描述 |
示例 |
|
字符类 |
匹配指定字符之一 |
|
|
否定字符类 |
匹配非指定字符 |
|
|
范围字符类 |
匹配指定范围内的字符 |
|
|
任意字符 |
匹配除换行符外的任意字符 |
|
|
数字 |
匹配数字(等价于 |
|
|
非数字 |
匹配非数字字符(等价于 |
|
|
单词字符 |
匹配字母、数字或下划线(等价于 |
|
|
非单词字符 |
匹配非字母、数字、下划线 |
|
|
空白字符 |
匹配空格、制表符、换行符等 |
|
|
非空白字符 |
匹配非空白字符 |
|
|
行首 |
匹配行首位置 |
|
|
行尾 |
匹配行尾位置 |
|
|
单词边界 |
匹配单词的开始或结束位置 |
|
|
0次或1次量词 |
匹配 X 0次或1次 |
|
|
0次或多次量词 |
匹配 X 0次或多次 |
|
|
1次或多次量词 |
匹配 X 至少1次 |
|
|
精确次数量词 |
匹配 X 恰好n次 |
|
|
最少次数量词 |
匹配 X 至少n次 |
|
|
范围次数量词 |
匹配 X 次数在n到m次之间(含) |
|
|
非贪婪量词 |
匹配最小可能的次数 |
|
|
捕获组 |
捕获匹配的子表达式 |
|
|
反向引用 |
引用第1个捕获组 |
|
|
非捕获组 |
分组但不捕获 |
|
`X |
Y` |
逻辑或 |
匹配 X 或 Y |
|
正向先行断言 |
匹配后面紧跟 X 的位置 |
|
|
负向先行断言 |
匹配后面不跟 X 的位置 |
|
|
正向后行断言 |
匹配前面是 X 的位置 |
|
|
负向后行断言 |
匹配前面不是 X 的位置 |
|
|
忽略大小写标志 |
后续匹配不区分大小写 |
|
注意事项:
- 转义字符:在 Java 字符串中,需用双反斜杠表示正则中的单反斜杠(如
\\d
表示\d
)。 - 标志修饰:可通过
Pattern.compile(regex, Pattern.CASE_INSENSITIVE)
或内嵌标志(如(?i)
)启用模式。 - 贪婪与非贪婪:默认量词是贪婪的(匹配最长),添加
?
变为非贪婪(匹配最短)。
此表格可作为快速查阅核心正则语法使用,适用于文本匹配、验证和提取等场景。
▶️ 代码示例:货币匹配
String text = "Prices: $99.99, ¥5000, 免费"; Pattern pattern = Pattern.compile("\\p{Sc}\\d+(?:\\.\\d+)?"); Matcher matcher = pattern.matcher(text); // 匹配结果:$99.99, ¥5000
⚙️ 第2章 Java正则API全解
2.1 Pattern类方法大全
(用层级结构表示核心方法关系)
Pattern 类(final) │ ├── **静态方法**(直接调用) │ ├── compile(String regex) → Pattern │ ├── compile(String regex, int flags) → Pattern │ ├── matches(String regex, CharSequence input) → boolean │ ├── quote(String s) → String │ └── asPredicate(String regex) → Predicate<String> (Java 8+) │ └── **实例方法**(需通过 `Pattern` 对象调用) ├── matcher(CharSequence input) → Matcher ├── flags() → int ├── pattern() → String ├── split(CharSequence input) → String[] ├── split(CharSequence input, int limit) → String[] ├── splitAsStream(CharSequence input) → Stream<String> (Java 8+) ├── asMatchPredicate() → Predicate<String> (Java 11+) └── asSplitPredicate() → Predicate<String> (Java 11+)
核心方法调用流程图
(用文本箭头模拟流程)
[用户输入正则表达式] │ ▼ compile(regex) → 创建 Pattern 对象 │ ├──→ matcher(input) → 生成 Matcher 对象 → 执行匹配/替换等操作 │ ├──→ split(input) → 分割字符串为数组 │ ├──→ flags() → 返回编译时标志 │ └──→ pattern() → 返回原始正则表达式 [快速调用(无需显式创建 Pattern)] │ ├──→ matches(regex, input) → 直接返回是否匹配 │ │ │ └──(内部调用:compile(regex).matcher(input).matches()) │ └──→ quote(s) → 转义特殊字符为字面量
图形总结
- 入口:通过
compile
创建Pattern
对象,或直接用静态方法。 - 操作分支:生成
Matcher
、分割字符串、获取元信息。 - 扩展性:Java 8+ 新增了与 Stream 和函数式接口的集成方法。
关键方法说明
compile(String regex)
- 核心入口:将正则表达式编译为
Pattern
对象(线程安全,可重复使用)。
matcher(CharSequence input)
- 生成
Matcher
对象,提供find()
,group()
,replaceAll()
等具体操作。
matches(String regex, CharSequence input)
- 快捷方法:等价于
compile(regex).matcher(input).matches()
。
split(CharSequence input)
- 按正则匹配结果分割字符串,类似
String.split()
但性能更优。
asPredicate()
- 将正则转换为
Predicate
,用于流式处理(如filter
操作)。
import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.stream.Stream; public class PatternExamples { public static void main(String[] args) { // 示例1:compile() + matcher() Pattern pattern = Pattern.compile("a.b"); Matcher matcher = pattern.matcher("aaxab"); while (matcher.find()) { System.out.println("Found: " + matcher.group()); // 输出: Found: axa } // 示例2:matches() 静态方法 boolean isMatch = Pattern.matches("\\d{3}-\\d{2}", "123-45"); System.out.println(isMatch); // 输出: true // 示例3:split() 分割字符串 String[] words = pattern.split("aaXabYacc"); // 结果: ["", "X", "Y", "c"] (按"a.b"分割) // 示例4:quote() 转义特殊字符 String literalRegex = Pattern.quote("a.b"); // 生成字面量正则: \Qa.b\E,匹配精确字符串"a.b" // 示例5:Java 8+ 流式处理 Stream<String> stream = Pattern.compile(",") .splitAsStream("a,b,c"); // 生成流: ["a", "b", "c"] } }
关键方法说明示例
compile(String regex)
// 创建可重用的Pattern对象 Pattern p = Pattern.compile("\\d+"); Matcher m = p.matcher("123abc");
matcher()
// 获取匹配器执行操作 while (matcher.find()) { System.out.println(matcher.group()); }
matches()
// 快速验证格式(如手机号) boolean isValid = Pattern.matches("1[3-9]\\d{9}", "13812345678");
split()
// 分割复杂字符串 String[] arr = Pattern.compile("[,\\s]+") .split("a, b,c d"); // 结果: ["a","b","c","d"]
asPredicate()
// Java8+ 过滤流数据 Stream.of("cat", "123").filter( Pattern.compile("\\d+").asPredicate() ); // 保留"123"
quote()
// 精确匹配包含特殊字符的字符串 String filePath = "file.txt"; boolean isMatch = Pattern.matches( Pattern.quote("file.txt"), filePath ); // 避免被解析为正则
完整流程图+代码示例
[用户输入正则表达式] │ ▼ Pattern.compile("a.c") → 创建对象 │ ├──→ matcher("abbcdef") → 生成Matcher │ ├── find() → 遍历匹配结果(如"abb") │ └── replaceAll("X") → "Xdef" │ ├──→ split("aaxab") → ["", "x", "b"] │ └──→ asPredicate() → 用于filter(s -> ...)
2.2 分组捕获实战
String html = "<h1>Hello Regex</h1>"; Pattern tagPattern = Pattern.compile("<([a-z][a-z0-9]*)[^>]*>(.*?)</\\1>"); Matcher m = tagPattern.matcher(html); if (m.find()) { System.out.println("Tag: " + m.group(1)); // 输出 h1 System.out.println("Content: " + m.group(2)); // Hello Regex }
🚀 第3章 性能优化黑科技
3.1 预编译模式提升300%性能
// 预编译正则表达式(适用于高频使用) private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w-_.+]*@[\\w-]+(\\.[\\w-]+)+$"); public boolean isValidEmail(String email) { return EMAIL_PATTERN.matcher(email).matches(); }
3.2 避免灾难性回溯的技巧
// 错误示例:嵌套量词导致指数级复杂度 Pattern dangerous = Pattern.compile("(a+)+b"); // 优化方案:使用原子分组 Pattern safe = Pattern.compile("(?>a+)+b");
🛠️ 第4章 10个必知实战场景
import java.util.regex.*; import java.util.stream.Collectors; public class RegexScenarios { public static void main(String[] args) { // 场景1:邮箱验证 System.out.println("邮箱验证:"); System.out.println(validateEmail("test@example.com")); // true System.out.println(validateEmail("invalid@.com")); // false // 场景2:手机号验证(中国大陆) System.out.println("\n手机号验证:"); System.out.println(validatePhone("13812345678")); // true System.out.println(validatePhone("1581234abcd")); // false // 场景3:密码强度检测 System.out.println("\n密码强度:"); System.out.println(checkPasswordStrength("Abc123!")); // 强 System.out.println(checkPasswordStrength("weakpass")); // 弱 // 场景4:提取URL中的域名 System.out.println("\n提取域名:"); extractDomain("https://www.example.com/path?query=1").forEach(System.out::println); // 场景5:日志时间戳提取 System.out.println("\n提取时间戳:"); extractTimestamps("[2023-08-15 14:30:22] ERROR occurred").forEach(System.out::println); // 场景6:替换敏感信息 System.out.println("\n替换敏感信息:"); System.out.println(maskCreditCard("Visa 4111-1111-1111-1112")); // 场景7:CSV解析 System.out.println("\nCSV解析:"); parseCSV("\"Name\",\"Age\",\"City\"\n\"John, Doe\",25,\"New York\"").forEach(System.out::println); // 场景8:HTML标签内容提取 System.out.println("\n提取HTML内容:"); extractHtmlContent("<h1>Title</h1><p>Content</p>").forEach(System.out::println); // 场景9:中文匹配 System.out.println("\n中文匹配:"); System.out.println(containsChinese("Hello 你好!")); // true // 场景10:日期格式验证 System.out.println("\n日期验证:"); System.out.println(validateDate("2023-02-29")); // false System.out.println(validateDate("2023-08-15")); // true } // 场景1:邮箱验证 static boolean validateEmail(String email) { return Pattern.matches("^[\\w.-]+@([\\w-]+\\.)+[a-zA-Z]{2,6}$", email); } // 场景2:手机号验证 static boolean validatePhone(String phone) { return Pattern.matches("^1[3-9]\\d{9}$", phone); } // 场景3:密码强度检测 static String checkPasswordStrength(String password) { boolean hasUpper = Pattern.compile("[A-Z]").matcher(password).find(); boolean hasLower = Pattern.compile("[a-z]").matcher(password).find(); boolean hasDigit = Pattern.compile("\\d").matcher(password).find(); boolean hasSpecial = Pattern.compile("[!@#$%^&*]").matcher(password).find(); return (password.length() >= 8 && hasUpper && hasLower && hasDigit && hasSpecial) ? "强" : "弱"; } // 场景4:提取URL域名 static List<String> extractDomain(String url) { Matcher m = Pattern.compile("https?://([\\w.-]+)").matcher(url); return m.find() ? List.of(m.group(1)) : List.of(); } // 场景5:提取日志时间戳 static List<String> extractTimestamps(String log) { return Pattern.compile("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}") .matcher(log) .results() .map(MatchResult::group) .collect(Collectors.toList()); } // 场景6:信用卡号脱敏 static String maskCreditCard(String text) { return text.replaceAll("\\b(\\d{4})-(\\d{4})-(\\d{2})\\d{2}-(\\d{4})\\b", "$1-****-**-$4"); } // 场景7:CSV解析(处理带逗号的字段) static List<List<String>> parseCSV(String csv) { Pattern pattern = Pattern.compile("(\"[^\"]*\"|[^,]+)"); return Arrays.stream(csv.split("\\r?\\n")) .map(line -> pattern.matcher(line) .results() .map(m -> m.group(1).replace("\"", "")) .collect(Collectors.toList())) .collect(Collectors.toList()); } // 场景8:提取HTML标签内容 static List<String> extractHtmlContent(String html) { return Pattern.compile("<[^>]+>([^<]+)</[^>]+>") .matcher(html) .results() .map(m -> m.group(1)) .collect(Collectors.toList()); } // 场景9:中文匹配 static boolean containsChinese(String text) { return Pattern.compile("[\\u4e00-\\u9fa5]").matcher(text).find(); } // 场景10:日期格式验证(简单版) static boolean validateDate(String date) { return Pattern.matches("^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$", date); } }
关键场景解释说明
- 邮箱验证
- 正则:
^[\w.-]+@([\w-]+\.)+[a-zA-Z]{2,6}$
- 说明:验证标准邮箱格式,支持带点域名(如.co.uk)
- 手机号验证
- 正则:
^1[3-9]\d{9}$
- 说明:验证中国大陆手机号,13-19开头,共11位
- 密码强度
- 规则:至少8位,包含大小写字母、数字和特殊字符
- 技巧:使用多个正则分别验证不同条件
- URL域名提取
- 正则:
https?://([\w.-]+)
- 用途:从URL中提取主域名(如www.example.com)
- 日志时间戳提取
- 正则:
\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
- 说明:匹配YYYY-MM-DD HH:MM:SS格式
- 信用卡脱敏
- 正则:
\b(\d{4})-(\d{4})-\d{2}(\d{2})-(\d{4})\b
- 结果:保留首尾4位,中间脱敏(如4111-****-**-1112)
- CSV解析
- 正则:
("[^"]*"|[^,]+)
- 处理:支持带逗号的引用字段(如"John, Doe")
- HTML内容提取
- 正则:
<[^>]+>([^<]+)</[^>]+>
- 注意:简单场景使用,复杂HTML建议用解析库
- 中文匹配
- 正则:
[\u4e00-\u9fa5]
- 说明:匹配所有中文字符
- 日期验证
- 正则:
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
- 局限:不验证闰年等复杂情况
注意:这些示例覆盖了正则表达式在验证、提取、替换、解析等场景的典型应用,建议根据实际需求调整正则表达式。对于关键业务场景(如信用卡验证),建议结合第三方验证库进行更严格的校验。
📊 第5章 可视化流程图解析
🚨 第6章 十大常见陷阱
- 贪婪匹配陷阱
// 错误示例:匹配HTML标签内容 Pattern.compile("<div>(.*)</div>"); // 会匹配到最后一个</div> // 正确方案:使用非贪婪模式 Pattern.compile("<div>(.*?)</div>");
- 未考虑Unicode字符
// 旧方法:仅匹配英文数字 Pattern.compile("\\w+"); // 新方案:支持Unicode(Java 17+) Pattern.compile("\\p{L}+");
🎯 结语:成为正则大师
通过本文的学习,您已经掌握了:
- Java正则表达式完整语法体系
- JDK 21最新API特性
- 生产环境性能优化方案
- 10+真实场景解决方案
附录工具推荐:
- Regex101 在线测试神器
立即动手:尝试用正则表达式解析您的项目日志文件,感受效率爆炸的提升!