跳到主要内容

Java 正则表达式

正则表达式是一种强大的文本处理工具,它允许我们基于特定模式搜索、匹配和操作字符串。在Java中,正则表达式通过java.util.regex包提供支持,主要包含PatternMatcher两个核心类。掌握正则表达式可以大幅提高我们处理文本的效率。

什么是正则表达式?

正则表达式(Regular Expression,简称regex)是一种用特定语法编写的模式,用来描述和匹配一系列符合某个句法规则的字符串。简单来说,它是一种用于文本搜索和替换的"模板"。

思考一下

想象你需要验证用户输入的是否是有效的电子邮箱地址,或者从一段文本中提取所有电话号码,手动编写代码会很复杂,而正则表达式可以用简洁的方式解决这些问题。

Java 中的正则表达式基础

在Java中使用正则表达式主要依靠两个类:

  • java.util.regex.Pattern:编译正则表达式为模式
  • java.util.regex.Matcher:使用模式对字符串执行匹配操作

基本使用步骤

  1. 编译正则表达式模式
  2. 获取匹配器
  3. 使用匹配器进行操作
java
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次

字符类

方括号[]内的字符表示"匹配其中任意一个字符":

java
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()方法检查整个字符串是否与模式匹配:

java
String text = "Hello123";
boolean isMatch = text.matches("\\w+");
System.out.println(isMatch); // 输出: true

find()和group()方法

find()方法查找下一个匹配,group()返回匹配的子串:

java
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()用于替换匹配的内容:

java
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. 电子邮箱验证

java
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

java
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. 密码强度验证

java
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

性能考虑

当多次使用同一个正则表达式时,应该预编译模式以提高效率:

java
// 低效方式 - 每次调用都编译正则表达式
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代码中需要使用两个反斜杠:

java
// 匹配字面上的"1+1=2"
Pattern pattern = Pattern.compile("1\\+1=2");
System.out.println("1+1=2".matches("1\\+1=2")); // 输出: true

分组和捕获

圆括号()用于创建分组,可以通过group(int)方法引用这些分组:

java
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. 贪婪与非贪婪匹配

默认情况下,量词是"贪婪"的,会尽可能多地匹配字符:

java
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>
}

使用?使量词变成"非贪婪"模式:

java
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标志可以更改这种行为:

java
String multiline = "Line1\nLine2";
Pattern pattern = Pattern.compile("Line1.*Line2", Pattern.DOTALL);
System.out.println(pattern.matcher(multiline).matches()); // 输出: true

总结

Java正则表达式是一种强大的字符串处理工具,通过PatternMatcher类提供功能。正确使用正则表达式可以大幅简化文本处理任务,如验证、搜索和替换。

关键要点:

  • 使用Pattern.compile()编译正则表达式
  • 使用Matcher类进行匹配操作
  • 熟悉基本语法和特殊字符
  • 预编译频繁使用的正则表达式以提升性能
  • 善用分组功能来提取信息
  • 理解贪婪与非贪婪匹配的区别

练习

  1. 编写一个正则表达式验证中国手机号码(11位数字,以1开头)
  2. 编写一个方法从文本中提取所有形如#标签#的内容
  3. 使用正则表达式替换文本中所有敏感词(如"密码"、"账号")为星号
  4. 验证输入字符串是否为有效的日期格式(yyyy-MM-dd)
  5. 编写一个方法统计文本中包含的单词数量(考虑英文单词边界)

进一步学习资源

要深入学习Java正则表达式,可以参考以下资源:

  • Java官方文档:java.util.regex包
  • 正则表达式在线测试工具(如regex101、regexr)
  • 《精通正则表达式》一书
  • Java Pattern类的API文档,了解更多标志和选项

记住:正则表达式是一项需要实践的技能,多做练习才能真正掌握!