2594 字
13 分钟

Java正则表达式详解

2026-02-01
浏览量 加载中...

Java正则表达式详解#

什么是正则表达式?#

正则表达式是一种用于匹配字符串中字符组合的模式。在Java中,正则表达式是通过java.util.regex包中的类实现的。

正则表达式的用途#

  1. 字符串匹配:检查字符串是否符合特定模式
  2. 字符串查找:在字符串中查找符合特定模式的子串
  3. 字符串替换:替换字符串中符合特定模式的部分
  4. 字符串分割:根据特定模式分割字符串
  5. 表单验证:验证用户输入是否符合要求

正则表达式的语法#

1. 字符类#

表达式描述
[abc]匹配方括号内的任意一个字符
[^abc]匹配除了方括号内的任意一个字符
[a-z]匹配a到z范围内的任意一个字符
[A-Z]匹配A到Z范围内的任意一个字符
[0-9]匹配0到9范围内的任意一个字符
[a-zA-Z]匹配a到z或A到Z范围内的任意一个字符
[a-zA-Z0-9]匹配a到z、A到Z或0到9范围内的任意一个字符

2. 预定义字符类#

表达式描述
.匹配任意一个字符(除了换行符)
\d匹配一个数字字符,等价于[0-9]
\D匹配一个非数字字符,等价于[^0-9]
\w匹配一个单词字符(字母、数字、下划线),等价于[a-zA-Z0-9_]
\W匹配一个非单词字符,等价于[^a-zA-Z0-9_]
\s匹配一个空白字符(空格、制表符、换行符等)
\S匹配一个非空白字符

3. 边界匹配器#

表达式描述
^匹配字符串的开始
$匹配字符串的结束
\b匹配单词边界
\B匹配非单词边界

4. 量词#

表达式描述
*匹配前面的表达式0次或多次,等价于{0,}
+匹配前面的表达式1次或多次,等价于{1,}
?匹配前面的表达式0次或1次,等价于{0,1}
{n}匹配前面的表达式恰好n次
{n,}匹配前面的表达式至少n次
{n,m}匹配前面的表达式至少n次,最多m次

5. 贪婪与非贪婪#

表达式描述
*?非贪婪匹配前面的表达式0次或多次
+?非贪婪匹配前面的表达式1次或多次
??非贪婪匹配前面的表达式0次或1次
{n,m}?非贪婪匹配前面的表达式至少n次,最多m次

6. 逻辑运算符#

表达式描述
``
(xyz)捕获组,匹配括号内的表达式并捕获匹配项
(?:xyz)非捕获组,匹配括号内的表达式但不捕获匹配项
(?<name>xyz)命名捕获组,匹配括号内的表达式并以指定名称捕获匹配项

7. 特殊字符#

表达式描述
\转义字符,用于匹配特殊字符本身
``
()捕获组
[]字符类
{}量词
^字符串开始
$字符串结束
.任意字符
*0次或多次
+1次或多次
?0次或1次

Java中使用正则表达式#

1. Pattern和Matcher类#

Java中使用PatternMatcher类来处理正则表达式。

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo {
public static void main(String[] args) {
// 正则表达式模式
String regex = "\\d{3}-\\d{3}-\\d{4}"; // 匹配电话号码格式
// 要匹配的字符串
String text = "我的电话号码是123-456-7890,你的电话号码是987-654-3210。";
// 编译正则表达式
Pattern pattern = Pattern.compile(regex);
// 创建Matcher对象
Matcher matcher = pattern.matcher(text);
// 查找所有匹配项
while (matcher.find()) {
System.out.println("找到匹配项: " + matcher.group());
System.out.println("开始位置: " + matcher.start());
System.out.println("结束位置: " + matcher.end());
}
}
}

2. String类中的正则表达式方法#

String类提供了一些使用正则表达式的方法:

2.1 matches()#

检查字符串是否完全匹配正则表达式。

String email = "user@example.com";
String emailRegex = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}";
boolean isValid = email.matches(emailRegex);
System.out.println("邮箱是否有效: " + isValid);

2.2 split()#

根据正则表达式分割字符串。

String text = "apple,banana,orange";
String[] fruits = text.split(",");
for (String fruit : fruits) {
System.out.println(fruit);
}

2.3 replaceAll()#

替换字符串中所有匹配正则表达式的部分。

String text = "Hello 123 World 456";
String replaced = text.replaceAll("\\d+", "*");
System.out.println("替换后: " + replaced); // 输出: Hello * World *

2.4 replaceFirst()#

替换字符串中第一个匹配正则表达式的部分。

String text = "Hello 123 World 456";
String replaced = text.replaceFirst("\\d+", "*");
System.out.println("替换后: " + replaced); // 输出: Hello * World 456

正则表达式的应用示例#

1. 验证邮箱#

public static boolean isValidEmail(String email) {
String regex = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}";
return email.matches(regex);
}

2. 验证电话号码#

public static boolean isValidPhone(String phone) {
String regex = "\\d{3}-\\d{3}-\\d{4}";
return phone.matches(regex);
}

3. 验证身份证号#

public static boolean isValidIdCard(String idCard) {
String regex = "[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]";
return idCard.matches(regex);
}

4. 验证URL#

public static boolean isValidUrl(String url) {
String regex = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)",
return url.matches(regex);
}

5. 提取HTML标签#

public static List<String> extractHtmlTags(String html) {
List<String> tags = new ArrayList<>();
String regex = "<([a-z][a-z0-9]*)\\b[^>]*>([\\s\\S]*?)<\\/\\1>";
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(html);
while (matcher.find()) {
tags.add(matcher.group());
}
return tags;
}

6. 替换空白字符#

public static String replaceWhitespace(String text) {
return text.replaceAll("\\s+", " ");
}

7. 提取数字#

public static List<String> extractNumbers(String text) {
List<String> numbers = new ArrayList<>();
String regex = "\\d+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
numbers.add(matcher.group());
}
return numbers;
}

8. 驼峰命名转换为下划线命名#

public static String camelToSnake(String camelCase) {
return camelCase.replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase();
}

9. 下划线命名转换为驼峰命名#

public static String snakeToCamel(String snakeCase) {
return Pattern.compile("_([a-z])").matcher(snakeCase).replaceAll(m -> m.group(1).toUpperCase());
}

10. 验证密码强度#

public static boolean isStrongPassword(String password) {
// 至少8个字符,包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符
String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$";
return password.matches(regex);
}

正则表达式的最佳实践#

1. 编译正则表达式#

对于频繁使用的正则表达式,应该编译成Pattern对象并缓存起来,以提高性能。

// 缓存Pattern对象
private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
public static boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}

2. 使用非捕获组#

对于不需要捕获的组,使用非捕获组(?:...)可以提高性能。

// 捕获组
Pattern pattern1 = Pattern.compile("(abc|def)");
// 非捕获组(更高效)
Pattern pattern2 = Pattern.compile("(?:abc|def)");

3. 避免回溯#

复杂的正则表达式可能会导致回溯,影响性能。应该:

  • 避免使用嵌套量词
  • 避免使用贪婪量词
  • 使用更具体的模式

4. 测试正则表达式#

在使用正则表达式之前,应该使用各种测试用例进行测试,确保它能正确匹配预期的字符串,同时不匹配非预期的字符串。

5. 文档化正则表达式#

复杂的正则表达式应该添加注释,说明其用途和工作原理。

/**
* 验证邮箱格式
* 规则:
* 1. 用户名部分:字母、数字、点、下划线、百分号、加号、减号
* 2. @符号
* 3. 域名部分:字母、数字、点、减号
* 4. 顶级域名:至少2个字母
*/
private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");

6. 处理转义字符#

在Java字符串中,反斜杠是转义字符,因此在正则表达式中使用反斜杠时,需要使用双反斜杠。

// 匹配一个数字
String regex = "\\d"; // 第一个反斜杠是Java字符串的转义字符

7. 考虑国际化#

在处理国际化字符串时,应该考虑不同语言的字符集。

// 匹配任何语言的字母
String regex = "\\p{L}+";

常见陷阱#

1. 贪婪匹配#

默认情况下,量词是贪婪的,会尽可能多地匹配字符。这可能会导致意外的结果。

String text = "<div>内容1</div><div>内容2</div>";
String regex = "<div>.*</div>";
// 匹配结果:<div>内容1</div><div>内容2</div>(整个字符串)
// 使用非贪婪匹配
String regexNonGreedy = "<div>.*?</div>";
// 匹配结果:<div>内容1</div>(第一个div)

2. 转义字符#

在Java字符串中,反斜杠是转义字符,因此在正则表达式中使用反斜杠时,需要使用双反斜杠。

// 错误的做法
String regex = "\d+"; // 这会被解释为\d+,但在Java字符串中,\d不是有效的转义序列
// 正确的做法
String regex = "\\d+"; // 使用双反斜杠

3. 性能问题#

复杂的正则表达式可能会导致性能问题,特别是在处理长字符串时。

// 可能导致回溯的正则表达式
String regex = "(a+)+b";
String text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
// 这会导致大量的回溯,可能会使程序崩溃

4. 边界匹配器#

忘记使用边界匹配器(如^$)可能会导致部分匹配。

String text = "123-456-7890";
String regex = "\\d{3}-\\d{3}-\\d{4}";
// 正确匹配
String text2 = "123-456-7890abc";
String regex2 = "\\d{3}-\\d{3}-\\d{4}";
// 也会匹配,因为它只匹配了字符串的一部分
// 正确的做法:使用边界匹配器
String regex3 = "^\\d{3}-\\d{3}-\\d{4}$";
// 只会匹配完全符合格式的字符串

5. 特殊字符#

忘记转义特殊字符可能会导致正则表达式无法正常工作。

String text = "文件.txt";
String regex = ".*\\.txt";
// 正确匹配
String text2 = "文件(name).txt";
String regex2 = ".*\(name\).*";
// 需要转义括号

总结#

正则表达式是一种强大的工具,用于匹配、查找、替换和分割字符串。Java提供了PatternMatcher类来处理正则表达式,以及String类中的一些便捷方法。

本文介绍了正则表达式的基本语法、Java中的使用方法、应用示例和最佳实践。希望本文能够帮助你更好地理解和使用正则表达式。

练习#

  1. 编写一个程序,使用正则表达式验证邮箱格式。

  2. 编写一个程序,使用正则表达式验证电话号码格式。

  3. 编写一个程序,使用正则表达式验证身份证号格式。

  4. 编写一个程序,使用正则表达式提取字符串中的所有数字。

  5. 编写一个程序,使用正则表达式替换字符串中的空白字符为单个空格。

  6. 编写一个程序,使用正则表达式将驼峰命名转换为下划线命名。

  7. 编写一个程序,使用正则表达式将下划线命名转换为驼峰命名。

  8. 编写一个程序,使用正则表达式验证密码强度。

  9. 编写一个程序,使用正则表达式提取HTML标签。

  10. 编写一个程序,使用正则表达式验证URL格式。

通过这些练习,你将更加熟悉正则表达式的使用,为后续的学习做好准备。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Java正则表达式详解
https://blog.vanilla.net.cn/posts/2026-02-05-java-regular-expressions/
作者
鹁鸪
发布于
2026-02-01
许可协议
CC BY-NC-SA 4.0

评论区

目录