什么是正则表达式?
正则表达式(Regular Expression)是一种强大的文本处理工具,用于匹配、查找、替换字符串。它是一种"模式描述语言",用特殊字符描述字符串的特征。
生活比喻
正则表达式就像一个"通缉令模板"。传统的方式是你写一个完整的名字去匹配,但正则表达式可以写一个"模式":姓名的第一个字是张,第二个字是两个字...这样就能匹配所有符合这个模式的人。正则表达式就是"描述模式的语言"。
正则表达式基础符号
字符类
| 符号 | 含义 | 示例 |
|---|---|---|
| . | 任意单个字符 | a.c匹配"abc" |
| \d | 任意数字 | \d\d匹配"12" |
| \D | 任意非数字 | \D+匹配"abc" |
| \w | 单词字符[a-zA-Z0-9_] | \w+匹配"hello" |
| \W | 非单词字符 | \W匹配"!" |
| \s | 空白字符 | 匹配空格、制表符 |
| [abc] | 字符集,a/b/c任一 | [aeiou]匹配元音 |
| [^abc] | 排除字符集 | [^0-9]非数字 |
| [a-z] | 字符范围 | [A-Za-z]所有字母 |
数量词
| 符号 | 含义 | 示例 |
|---|---|---|
| * | 0个或多个 | ab*c匹配"ac"/"abc"/"abbc" |
| + | 1个或多个 | ab+c匹配"abc"/"abbc" |
| ? | 0个或1个 | colou?r匹配"color"/"colour" |
| {n} | 恰好n个 | \d{11}匹配11位数字 |
| {n,} | 至少n个 | \d{6,}至少6位 |
| {n,m} | n到m个 | \d{6,8}6到8位 |
位置词
| 符号 | 含义 | 示例 |
|---|---|---|
| ^ | 字符串开头 | ^hello匹配"hello world" |
| $ | 字符串结尾 | world$匹配"hello world" |
| \b | 单词边界 | \bword\b完整单词"word" |
分组和引用
| 符号 | 含义 | 示例 |
|---|---|---|
| (abc) | 捕获组 | (\d{4})-(\d{2})两组 |
| (?:abc) | 非捕获组 | 不创建分组引用 |
| \1 | 引用第一个组 | (\w)\1重复字符 |
Java中如何使用正则
1. 验证:matches()
public class RegexMatchesDemo {
public static void main(String[] args) {
String phone = "13812345678";
// 手机号:1开头,第二位3-9,11位数字
boolean valid = phone.matches("^1[3-9]\\d{9}$");
System.out.println("手机号有效: " + valid);
// 邮箱
String email = "user@example.com";
boolean emailValid = email.matches("^[\\w.-]+@[\\w.-]+\\.\\w+$");
System.out.println("邮箱有效: " + emailValid);
// 身份证号(18位)
String id = "110101199001011234";
boolean idValid = id.matches("^\\d{17}[\\dXx]$");
System.out.println("身份证有效: " + idValid);
}
}
2. 查找:Pattern和Matcher
import java.util.regex.*;
public class RegexFindDemo {
public static void main(String[] args) {
String text = "订单号: A123, B456, C789";
// 查找所有订单号
Pattern pattern = Pattern.compile("[A-Z]\\d{3}");
Matcher matcher = pattern.matcher(text);
System.out.println("找到的订单号:");
while (matcher.find()) {
System.out.println(" 位置" + matcher.start() + ": " + matcher.group());
}
}
}
3. 替换:replaceAll()
public class RegexReplaceDemo {
public static void main(String[] args) {
String text = "电话号码: 13812345678, 13998765432";
// 手机号脱敏:138****5678
String masked = text.replaceAll(
"(\\d{3})\\d{4}(\\d{4})",
"$1****$2"
);
System.out.println("脱敏后: " + masked);
// 替换所有数字
String noDigits = text.replaceAll("\\d+", "#");
System.out.println("数字替换: " + noDigits);
// 替换空白
String normalized = "你 好 世 界";
String noSpaces = normalized.replaceAll("\\s+", "");
System.out.println("去空白: " + noSpaces);
}
}
4. 分割:split()
public class RegexSplitDemo {
public static void main(String[] args) {
String csv = "苹果,香蕉,樱桃,日期";
// 按逗号分割
String[] fruits = csv.split(",");
System.out.println("水果: " + java.util.Arrays.toString(fruits));
// 按多种分隔符分割
String mixed = "苹果,香蕉;樱桃:日期";
String[] mixedFruits = mixed.split("[,;:]");
System.out.println("混合分割: " + java.util.Arrays.toString(mixedFruits));
// 按连续空白分割
String spaced = "苹果 香蕉 樱桃";
String[] spacedFruits = spaced.split("\\s+");
System.out.println("空白分割: " + java.util.Arrays.toString(spacedFruits));
}
}
常用正则表达式模板
| 用途 | 正则表达式 |
|---|---|
| 手机号(中国) | ^1[3-9]\d{9}$ |
| 电子邮箱 | ^[\w.-]+@[\w.-]+\.\w+$ |
| URL | ^https?://[\w.-]+(/[\w.-]*)*/?$ |
| IP地址 | ^(\d{1,3}\.){3}\d{1,3}$ |
| 日期(YYYY-MM-DD) | ^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ |
| 时间(HH:mm:ss) | ^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$ |
| 中文姓名 | ^[\u4e00-\u9fa5]{2,4}$ |
| QQ号 | ^[1-9]\d{4,10}$ |
| 邮政编码 | ^\d{6}$ |
捕获组示例
import java.util.regex.*;
public class RegexGroupDemo {
public static void main(String[] args) {
String text = "2026-06-15 10:30:45";
// 提取日期和时间
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})");
Matcher m = p.matcher(text);
if (m.matches()) {
System.out.println("完整匹配: " + m.group(0)); // 整个字符串
System.out.println("年: " + m.group(1)); // 2026
System.out.println("月: " + m.group(2)); // 06
System.out.println("日: " + m.group(3)); // 15
System.out.println("时: " + m.group(4)); // 10
System.out.println("分: " + m.group(5)); // 30
System.out.println("秒: " + m.group(6)); // 45
}
// 交换姓名
String names = "Zhang San, Li Si, Wang Wu";
String swapped = names.replaceAll("(\\w+)\\s+(\\w+)", "$2 $1");
System.out.println("姓名交换: " + swapped);
}
}
常见错误
错误1:忘记转义
在正则表达式中,.、*等是特殊字符。如果你要匹配字面意义上的点号,需要写成\\.。
// 错误:匹配任何字符
"example.com".matches(".+\\.com"); // true
// 正确:匹配字面意义的点号
"exampleXcom".matches(".+\\.com"); // false
错误2:贪婪匹配导致意外结果
.*是贪婪的,会尽可能多地匹配。使用.*?进行非贪婪匹配。
小结
- 正则表达式是强大的文本匹配和处理工具
- .匹配任意字符,\d匹配数字,\w匹配单词字符
- *+?表示数量,{n,m}表示范围
- ^$表示位置,\b表示单词边界
- Pattern/Matcher是Java中处理正则的主要类
- 捕获组()可以提取和复用匹配的子串