Java 正则表达式
正则表达式是一种强大的文本处理工具,它允许我们基于特定模式搜索、匹配和操作字符串。在Java中,正则表达式通过java.util.regex
包提供支持,主要包含Pattern
和Matcher
两个核心类。掌握正则表达式可以大幅提高我们处理文本的效率。
什么是正则表达式?
正则表达式(Regular Expression,简称regex)是一种用特定语法编写的模式,用来描述和匹配一系列符合某个句法规则的字符串。简单来说,它是一种用于文本搜索和替换的"模板"。
想象你需要验证用户输入的是否是有效的电子邮箱地址,或者从一段文本中提取所有电话号码,手动编写代码会很复杂,而正则表达式可以用简洁的方式解决这些问题。
Java 中的正则表达式基础
在Java中使用正则表达式主要依靠两个类:
java.util.regex.Pattern
:编译正则表达式为模式java.util.regex.Matcher
:使用模式对字符串执行匹配操作
基本使用步骤
- 编译正则表达式模式
- 获取匹配器
- 使用匹配器进行操作
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexBasic {
public static void main(String[] args) {
// 1. 编译正则表达式
Pattern pattern = Pattern.compile("Hello");
// 2. 获取匹配器
Matcher matcher = pattern.matcher("Hello World");
// 3. 进行匹配操作
boolean found = matcher.find();
System.out.println("匹配结果: " + found);
}
}
输出:
匹配结果: true
正则表达式语法
基本字符匹配
表达式 | 说明 |
---|---|
x | 字符x |
. | 任何字符 |
\d | 数字: [0-9] |
\D | 非数字: [^0-9] |
\s | 空白字符: [ \t\n\x0B\f\r] |
\S | 非空白字符: [^\s] |
\w | 单词字符: [a-zA-Z_0-9] |
\W | 非单词字符 |
量词
表达式 | 说明 |
---|---|
X? | X出现一次或不出现 |
X* | X出现零次或多次 |
X+ | X出现一次或多次 |
X{n} | X恰好出现n次 |
X{n,} | X至少出现n次 |
X{n,m} | X至少出现n次,但不超过m次 |
字符类
方括号[]
内的字符表示"匹配其中任意一个字符":
Pattern pattern = Pattern.compile("[abc]"); // 匹配a、b或c中的任意一个
Matcher matcher = pattern.matcher("apple");
boolean found = matcher.find();
System.out.println(found); // 输出: true,因为"apple"包含"a"
边界匹配
表达式 | 说明 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词边界 |
\B | 非单词边界 |
常用正则表达式方法
matches()方法
matches()
方法检查整个字符串是否与模式匹配:
String text = "Hello123";
boolean isMatch = text.matches("\\w+");
System.out.println(isMatch); // 输出: true
find()和group()方法
find()
方法查找下一个匹配,group()
返回匹配的子串:
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("There are 123 apples and 456 oranges");
while (matcher.find()) {
System.out.println("找到: " + matcher.group());
}
输出:
找到: 123
找到: 456
替换方法
replaceAll()
和replaceFirst()
用于替换匹配的内容:
String text = "My phone number is 123-456-7890";
String newText = text.replaceAll("\\d+", "XXX");
System.out.println(newText); // 输出: My phone number is XXX-XXX-XXX
实际应用场景
1. 电子邮箱验证
public static boolean isValidEmail(String email) {
String regex = "^[A-Za-z0-9+_.-]+@(.+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(email);
return matcher.matches();
}
// 使用示例
System.out.println(isValidEmail("user@example.com")); // true
System.out.println(isValidEmail("invalid-email")); // false
2. 从文本中提取所有URL
public static void extractUrls(String text) {
String urlRegex = "https?://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
Pattern pattern = Pattern.compile(urlRegex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("找到URL: " + matcher.group());
}
}
// 使用示例
String text = "访问 https://www.example.com 和 http://example.org 获取更多信息";
extractUrls(text);
输出:
找到URL: https://www.example.com
找到URL: http://example.org
3. 密码强度验证
public static boolean isStrongPassword(String password) {
// 至少8位,包含大写字母、小写字母、数字和特殊字符
String regex = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$";
return password.matches(regex);
}
// 使用示例
System.out.println(isStrongPassword("Abc@1234")); // true
System.out.println(isStrongPassword("weakpwd")); // false
性能考虑
当多次使用同一个正则表达式时,应该预编译模式以提高效率:
// 低效方式 - 每次调用都编译正则表达式
public static boolean isEmail1(String email) {
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
// 高效方式 - 只编译一次
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^[A-Za-z0-9+_.-]+@(.+)$");
public static boolean isEmail2(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
预编译的正则表达式模式应该声明为静态常量,以避免重复编译带来的性能损失。
转义特殊字符
正则表达式中的特殊字符(如 .*+?^$()[]{}|\
)如果要当普通字符匹配,需要使用反斜杠转义。但由于Java字符串本身也使用反斜杠作为转义字符,所以在Java代码中需要使用两个反斜杠:
// 匹配字面上的"1+1=2"
Pattern pattern = Pattern.compile("1\\+1=2");
System.out.println("1+1=2".matches("1\\+1=2")); // 输出: true
分组和捕获
圆括号()
用于创建分组,可以通过group(int)
方法引用这些分组:
Pattern pattern = Pattern.compile("(\\w+)@(\\w+\\.\\w+)");
Matcher matcher = pattern.matcher("contact@example.com");
if (matcher.matches()) {
System.out.println("完整匹配: " + matcher.group(0));
System.out.println("用户名: " + matcher.group(1));
System.out.println("域名: " + matcher.group(2));
}
输出:
完整匹配: contact@example.com
用户名: contact
域名: example.com
常见错误和调试技巧
1. 贪婪与非贪婪匹配
默认情况下,量词是"贪婪"的,会尽可能多地匹配字符:
String text = "<div>内容1</div><div>内容2</div>";
Pattern pattern = Pattern.compile("<div>.*</div>");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println(matcher.group()); // 输出: <div>内容1</div><div>内容2</div>
}
使用?
使量词变成"非贪婪"模式:
Pattern pattern = Pattern.compile("<div>.*?</div>");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(matcher.group());
}
输出:
<div>内容1</div>
<div>内容2</div>
2. 使用Pattern.DOTALL标志
默认情况下,.
不匹配换行符。使用DOTALL
标志可以更改这种行为:
String multiline = "Line1\nLine2";
Pattern pattern = Pattern.compile("Line1.*Line2", Pattern.DOTALL);
System.out.println(pattern.matcher(multiline).matches()); // 输出: true
总结
Java正则表达式是一种强大的字符串处理工具,通过Pattern
和Matcher
类提供功能。正确使用正则表达式可以大幅简化文本处理任务,如验证、搜索和替换。
关键要点:
- 使用
Pattern.compile()
编译正则表达式 - 使用
Matcher
类进行匹配操作 - 熟悉基本语法和特殊字符
- 预编译频繁使用的正则表达式以提升性能
- 善用分组功能来提取信息
- 理解贪婪与非贪婪匹配的区别
练习
- 编写一个正则表达式验证中国手机号码(11位数字,以1开头)
- 编写一个方法从文本中提取所有形如
#标签#
的内容 - 使用正则表达式替换文本中所有敏感词(如"密码"、"账号")为星号
- 验证输入字符串是否为有效的日期格式(yyyy-MM-dd)
- 编写一个方法统计文本中包含的单词数量(考虑英文单词边界)
进一步学习资源
要深入学习Java正则表达式,可以参考以下资源:
- Java官方文档:java.util.regex包
- 正则表达式在线测试工具(如regex101、regexr)
- 《精通正则表达式》一书
- Java Pattern类的API文档,了解更多标志和选项
记住:正则表达式是一项需要实践的技能,多做练习才能真正掌握!