正则表达式:从基础概念到 Java 实战应用
在日常编程开发中,字符串的匹配、分割、替换等操作十分常见 —— 比如验证用户输入的邮箱格式、从文本中提取特定信息、按多种规则拆分字符串等。而正则表达式(Regular Expression)作为一种强大的文本处理工具,能高效解决这类问题。本文将从基础概念切入,结合实例解析正则表达式,并完整展示其在 Java 中的实现方案。
一、正则表达式基本概念
1. 定义
正则表达式(简称 Regex)是一种用于描述字符串模式的特殊文本串,它可以:
- 检查一个字符串是否符合指定模式(如 “是否为合法手机号”);
- 从字符串中提取符合模式的内容(如 “提取文本中的所有数字”);
- 替换字符串中符合模式的部分(如 “将所有敏感字符替换为 *”)。
正则表达式广泛应用于数据验证、日志分析、文本爬虫等场景,是开发者必备的工具之一。
2. 核心组成元素
正则表达式的功能由元字符、量词、字符类等核心元素组合实现,以下是最常用的元素说明:
| 元素类型 | 具体符号 / 语法 | 含义说明 |
|---|---|---|
| 元字符 | . |
匹配任意单个字符(除换行符\n外),如a.b可匹配acb、aab等 |
^ |
匹配字符串的开头,如^Hello仅匹配以 “Hello” 开头的字符串 |
|
$ |
匹配字符串的结尾,如World$仅匹配以 “World” 结尾的字符串 |
|
| |
逻辑 “或”,匹配左右任意一个模式,如cat|dog可匹配 “cat” 或 “dog” |
|
\ |
转义字符,用于匹配元字符本身(如\.匹配实际的 “.”,\*匹配实际的 “*”) |
|
| 量词 | * |
匹配前面的元素零次或多次,如a*可匹配 “”(空串)、“a”、“aa” 等 |
+ |
匹配前面的元素一次或多次,如a+可匹配 “a”、“aa”,但不匹配空串 |
|
? |
匹配前面的元素零次或一次,如a?可匹配 “” 或 “a” |
|
{n} |
匹配前面的元素恰好 n 次,如a{3}仅匹配 “aaa” |
|
{n,} |
匹配前面的元素至少 n 次,如a{2,}可匹配 “aa”、“aaa” 等 |
|
{n,m} |
匹配前面的元素n 到 m 次(含 n 和 m),如a{2,3}可匹配 “aa”、“aaa” |
|
| 字符类 | [abc] |
匹配 “a”“b”“c” 中的任意一个字符,等价于a|b|c |
[a-z] |
匹配任意小写字母(范围匹配),同理[0-9]匹配任意数字,[A-Z]匹配大写字母 |
|
[^abc] |
匹配 “非 a、非 b、非 c” 的任意字符(^ 在中括号内表示 “非”) | |
| 预定义字符类 | \d |
等价于[0-9],匹配任意数字 |
\s |
匹配任意空白字符(空格、制表符\t、换行符\n等) |
|
\w |
等价于[a-zA-Z0-9_],匹配字母、数字或下划线 |
二、正则表达式常用示例
掌握基础元素后,可组合出满足实际需求的正则表达式,以下是典型场景示例:
1. 数据格式验证
-
验证邮箱:
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,}$解析:^[a-zA-Z0-9_-]+:邮箱前缀(字母、数字、下划线、短横线,至少 1 位);@:固定的 “@” 符号;[a-zA-Z0-9_-]+:邮箱域名(如gmail、163);\.[a-zA-Z]{2,}:域名后缀(如.com、.cn,至少 2 位字母);$:匹配字符串结尾,避免后缀后多无关字符。
-
验证手机号(中国大陆):
^1[3-9]\d{9}$解析:^1:以 “1” 开头(手机号固定规则);[3-9]:第二位为 3-9(排除 1、2,对应运营商号段);\d{9}:后续 9 位为数字(总长度 11 位);$:匹配结尾,确保无多余字符。
-
验证整数或小数:
^-?\d+(\.\d+)?$解析:^-?:可选的负号(匹配正数或负数);\d+:至少 1 位整数部分;(\.\d+)?:可选的小数部分(.+ 至少 1 位数字);$:匹配结尾。
2. 字符串分割
- 按单个分隔符分割:如按空格分割 “one two three”,正则为
" "; - 按多个分隔符分割:如按
;、,、?分割 “abc;123,456?999|haha”,正则为";|,|\\?"(?是元字符,需用\转义,Java 中需写\\?); - 按任意空白字符分割:正则为
"\\s+"(匹配 1 个或多个空白字符,避免多个空格导致空数组元素)。
3. 内容提取与替换
- 提取文本中的所有数字:
\d+(匹配 1 个或多个数字); - 替换敏感字符:如将字符串中的数字替换为
*,正则为"\d"; - 去除首尾空格:
^(\s+)|(\s+)$(匹配开头或结尾的 1 个或多个空白字符,替换为空串)。
三、正则表达式的 Java 实现
Java 提供两种使用正则表达式的方式:
String类内置方法:适合简单场景(分割、匹配、替换);java.util.regex包:Pattern(编译正则)和Matcher(执行匹配),适合复杂场景(多次匹配、提取子串)。
1. String类的正则方法
String类提供split()、matches()、replaceAll()等便捷方法,无需额外创建类实例。
(1)split(String regex):按正则分割字符串
将字符串按匹配的正则规则拆分为字符串数组,示例如下:
public class RegexSplitDemo {
public static void main(String[] args) {
// 待分割字符串(含;、,、?三种分隔符)
String str = "abc;123,456?999|haha";
// 正则表达式:匹配;、,或?(?需转义为\\?)
String regex = ";|,|\\?";
// 执行分割
String[] result = str.split(regex);
// 输出结果
System.out.println("分割后的数组:");
for (int i = 0; i < result.length; i++) {
System.out.printf("元素[%d]:%s%n", i, result[i]);
}
}
}
输出结果:
plaintext
分割后的数组:
元素[0]:abc
元素[1]:123
元素[2]:456
元素[3]:999|haha
(2)matches(String regex):验证字符串是否匹配正则
返回boolean值,true表示完全匹配正则规则(注意:需匹配整个字符串,而非部分),示例如下:
java
运行
public class RegexMatchDemo {
public static void main(String[] args) {
// 待验证的邮箱和手机号
String validEmail = "test_123@example.com";
String invalidEmail = "test@.com"; // 非法域名
String validPhone = "13812345678";
String invalidPhone = "12345678901"; // 第二位为2,非法
// 正则表达式
String emailRegex = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\\.[a-zA-Z]{2,}$";
String phoneRegex = "^1[3-9]\\d{9}$";
// 执行验证
System.out.printf("邮箱[%s]是否合法:%b%n", validEmail, validEmail.matches(emailRegex));
System.out.printf("邮箱[%s]是否合法:%b%n", invalidEmail, invalidEmail.matches(emailRegex));
System.out.printf("手机号[%s]是否合法:%b%n", validPhone, validPhone.matches(phoneRegex));
System.out.printf("手机号[%s]是否合法:%b%n", invalidPhone, invalidPhone.matches(phoneRegex));
}
}
输出结果:
plaintext
邮箱[test_123@example.com]是否合法:true
邮箱[test@.com]是否合法:false
手机号[13812345678]是否合法:true
手机号[12345678901]是否合法:false
(3)replaceAll(String regex, String replacement):按正则替换
将字符串中所有匹配正则的部分替换为replacement,示例如下:
public class RegexReplaceDemo {
public static void main(String[] args) {
// 待处理字符串
String strWithNum = "Hello123World456"; // 含数字
String strWithSpace = " 正则表达式 实战 "; // 首尾空格
// 1. 将所有数字替换为*
String noNumStr = strWithNum.replaceAll("\\d", "*");
// 2. 去除首尾空格(匹配开头/结尾的空白字符,替换为空串)
String noSpaceStr = strWithSpace.replaceAll("^(\\s+)|(\\s+)$", "");
// 输出结果
System.out.printf("原字符串:%s%n替换数字后:%s%n", strWithNum, noNumStr);
System.out.printf("原字符串:[%s]%n去除空格后:[%s]%n", strWithSpace, noSpaceStr);
}
}
输出结果:
plaintext
原字符串:Hello123World456
替换数字后:Hello***World***
原字符串:[ 正则表达式 实战 ]
去除空格后:[正则表达式 实战]
2. Pattern与Matcher的高级用法
当需要多次匹配(如提取文本中所有符合规则的内容)或获取匹配子串的位置时,需使用Pattern和Matcher:
Pattern:编译正则表达式(避免重复编译,提高效率);Matcher:关联待匹配字符串,执行匹配操作。
示例:提取文本中的所有温度值
java
运行
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExtractDemo {
public static void main(String[] args) {
// 待提取的文本
String text = "今天气温25℃,明天预计30℃,后天可能28℃,大后天降温至18℃。";
// 正则表达式:匹配1个或多个数字(温度值)
String regex = "\\d+";
// 1. 编译正则表达式(仅需编译一次,可重复使用)
Pattern pattern = Pattern.compile(regex);
// 2. 关联待匹配字符串,创建Matcher对象
Matcher matcher = pattern.matcher(text);
// 3. 提取所有匹配的内容(find()查找下一个匹配项)
System.out.println("文本中的温度值:");
int count = 0;
while (matcher.find()) {
count++;
// group():返回当前匹配的子串;start()/end():返回匹配子串的起始/结束索引
System.out.printf("第%d个温度:%s(位置:%d-%d)%n",
count, matcher.group(), matcher.start(), matcher.end()-1);
}
}
}
输出结果:
plaintext
文本中的温度值:
第1个温度:25(位置:4-5)
第2个温度:30(位置:12-13)
第3个温度:28(位置:20-21)
第4个温度:18(位置:29-30)
3. 与StringTokenizer的对比
参考文档中提到的StringTokenizer类也可用于分割字符串,但它不支持正则表达式,仅能按固定字符分割,灵活性远低于正则:
StringTokenizer:如按 “-” 分割 “2024-10-20”,需指定分隔符"-",无法处理 “2024/10-20”(混合分隔符);- 正则
split():处理混合分隔符仅需"\\/|-"(匹配/或-),无需额外逻辑。
因此,复杂分割场景优先使用正则表达式的split()方法。
四、总结与实践建议
1. 核心优势
正则表达式的核心价值在于用简洁的语法描述复杂的字符串模式,减少冗余的字符串判断代码(如验证邮箱无需逐字符判断,仅需一行正则)。
2. 实践建议
- 先测试再使用:复杂正则建议用在线工具(如Regex101)验证,避免语法错误;
- 避免过度复杂:过于冗长的正则(如匹配所有 URL)可拆分为多个步骤,兼顾可读性和维护性;
- 注意转义字符:Java 中
\需写为\\(如\d需写\\d),避免与 Java 的字符串转义冲突; - 复用
Pattern:多次使用同一正则时,提前编译Pattern(而非每次调用String方法),减少重复编译开销。
更多推荐


所有评论(0)