正则表达式
maiaimei 2025/9/30 Java
正则表达式 (opens new window)(Regular Expression,简称 Regex 或 RegExp)是一种用来匹配字符串中字符组合的模式。
正则表达式是一种用于模式匹配和搜索文本的工具。
正则表达式提供了一种灵活且强大的方式来查找、替换、验证和提取文本数据。
正则表达式可以应用于各种编程语言和文本处理工具中,如 JavaScript、Python、Java、Perl 等。
# Metacharacters
元字符 (opens new window)(Metacharacters):在正则表达式中有特殊含义的字符。下面是一些常见的正则表达式元字符:
符合 | 含义 | 示例 | |
---|---|---|---|
基本元字符 | **点号. ** | 匹配除换行符之外的任何单个字符。 | a.c 匹配"abc"、"a#c"、"a1c"等 |
基本元字符 | **反斜杠\ ** | 转义字符,用于转义元字符, 使后面的字符失去特殊含义,使其表示其本身。 | \. 匹配实际的点号字符"." |
基本元字符 | **脱字符^ ** | 定位符。当在方括号表达式外时,表示行的开始; 否定字符类。在方括号表达式内,表示否定或排除。 | ^abc 匹配以"abc"开始的字符串[^a] 匹配非"a"的任意字符 |
基本元字符 | **美元符号$ ** | 定位符。表示行的结束。 | abc$ 匹配以"abc"结束的字符串 |
字符类元字符 | 方括号[] | 定义字符集合,匹配其中任意一个字符 | [aeiou] 匹配任意一个元音字母 |
字符类元字符 | 否定字符类[^] | 匹配不在方括号中的任意字符 | [^0-9] 匹配任意非数字字符 |
字符类元字符 | 连字符- | 在字符类中表示范围 | [a-z] 匹配任意小写字母 |
量词元字符 | 问号? | 限定符。匹配前面的子表达式零次或一次。默认情况下,量词(* , + , ? , {} )是贪婪的,会尽可能多地匹配字符。在量词后加? 可使其变为非贪婪(懒惰)模式。 | ab?c 匹配"ac"和"abc" |
量词元字符 | 星号* | 限定符。匹配前面的子表达式零次或多次。 | ab*c" 匹配"ac"、"abc"、"abbc"、"abbbc"等 |
量词元字符 | **加号+ ** | 限定符。匹配前面的子表达式一次或多次。 | ab+c 匹配"abc"、"abbc"、"abbbc"等,但不匹配"ac" |
量词元字符 | 花括号{n} | 限定符。精确匹配n次。 | a{3} 匹配 "aaa" |
量词元字符 | {n,} | 限定符。至少匹配n次。 | a{2,} 匹配 "aa", "aaa" 等 |
量词元字符 | {n,m} | 限定符。匹配n到m次。 | a{2,4} 匹配 "aa", "aaa", "aaaa" |
贪婪与非贪婪量词 | *? | 限定符。零次或多次,但尽可能少。 默认情况下,量词( * , + , ? , {} )是贪婪的,会尽可能多地匹配字符。在量词后加? 可使其变为非贪婪(懒惰)模式。 | <.*?> 匹配HTML标签时不会跨标签匹配 |
贪婪与非贪婪量词 | +? | 限定符。一次或多次,但尽可能少 | |
贪婪与非贪婪量词 | ?? | 限定符。零次或一次,但尽可能少 | |
贪婪与非贪婪量词 | {n,m}? | 限定符。n到m次,但尽可能少 | |
分组元字符 | (pattern) | 定义子表达式或捕获组。 捕获分组元字符,非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号。 | (ab)+ 匹配 "ab", "abab" 等 |
分组元字符 | (?<name>pattern) | 捕获分组元字符,命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号 替代尖括号,例如(?'name') | |
非捕获分组元字符 | (?:pattern) | 一个非捕获分组(Non-capturing group),它用于对正则表达式进行分组,但不会创建反向引用。这种分组方式比普通的捕获分组。它的特点和用法: 1. 提高性能 - 不需要存储匹配的内容 2. 代码更清晰 - 明确表示这个组不需要被引用 3. 减少内存使用 - 不会创建额外的捕获组 | (?:jpg|jpeg|png) 匹配 jpg 或 jpeg 或 png 文件扩展名 |
非捕获分组元字符 | (?=pattern) | 正向肯定预查。匹配后面跟着特定模式的位置。一种前瞻性断言(Positive Lookahead)的非捕获分组,它用于匹配某个位置,这个位置的后面必须匹配指定的pattern,但不会消耗这些字符。它的特点和用法: 1. 匹配一个位置,这个位置后面的字符要满足pattern 2. 不会将pattern部分包含在最终的匹配结果中 3. 不会消耗字符,只是检查是否满足条件 | Windows(?=95|98|NT|2000) 匹配"Windows2000"中的“Windows",但不匹配“Windows3.1"中的"Windows"。 |
非捕获分组元字符 | (?!pattern) | 正向否定预查。匹配后面不跟着特定模式的位置。一种负向前瞻断言(Negative Lookahead),它用于匹配某个位置,这个位置的后面不能匹配指定的pattern。这是一个非捕获分组,不会消耗任何字符。它的特点和用法: 1. 匹配一个位置,这个位置后面的字符不能满足pattern 2. 不会消耗字符,只是检查条件 3. 不会捕获匹配内容 | Windows(?!95|98|NT|2000) 匹配"Windows3.1"中的“Windows",但不匹配“Windows2000"中的"Windows"。 |
非捕获分组元字符 | (?<=pattern) | 反向肯定预查。匹配前面是特定模式的位置。 | (?<=95|98)Windows 匹配前面是95或98的"Windows" |
非捕获分组元字符 | (?<!pattern) | 反向否定预查。匹配前面不是特定模式的位置。 | (?<!95|98)Windows 匹配前面不是95或98的"Windows" |
反向引用 | 反斜杠加数字(例如,\1 ) | 用于引用捕获组的语法。 反向引用(Backreference)允许我们在正则表达式中(模式内)引用之前捕获组匹配到的内容。 它使用 \1 \2 等来引用前面的捕获组。例如:\1 引用第一个捕获组,\2 引用第二个捕获组,以此类推。反向引用是正则表达式中一个强大的功能,它允许我们匹配重复的内容或验证对称的模式。在处理HTML/XML标签、查找重复内容、验证输入等场景中特别有用。使用时需要注意捕获组的编号和作用范围,以及非捕获组不能被引用的限制。 \1 的用法:1. 用在正则表达式模式内部 2. 用于匹配与第一个捕获组相同的内容 $1 的用法:1. 用在替换字符串中 2. 用于引用正则表达式中捕获的组 | (ab)c\\1 匹配"abcab" |
选择元字符 | **竖线| ** | 表示"或"关系,用于分隔两个或多个可能的匹配模式。 | cat|dog 匹配 "cat" 或 "dog" |
特殊字符类元字符 | \d | 匹配任意数字,等价于 [0-9] | |
特殊字符类元字符 | \D | 匹配任意非数字,等价于 [^0-9] | |
特殊字符类元字符 | \w | 匹配任意单词字符(字母、数字、下划线),等价于 [a-zA-Z0-9_] | |
特殊字符类元字符 | \W | 匹配任意非单词字符,等价于 [^a-zA-Z0-9_] | |
特殊字符类元字符 | \s | 匹配任意空白字符(空格、制表符、换行符等) | |
特殊字符类元字符 | \S | 匹配任意非空白字符 | |
边界匹配元字符 | \b | 定位符。匹配单词边界 | \bcat\b 匹配 "cat" 但不匹配 "category" |
边界匹配元字符 | \B | 定位符。匹配非单词边界 | \Bcat\B 匹配 "scattered" 中的 "cat" 但不匹配单独的 "cat" |
其他元字符 | \n | 匹配换行符 | |
其他元字符 | \t | 匹配制表符 | |
其他元字符 | \r | 匹配回车符 | |
其他元字符 | \f | 匹配换页符 | |
其他元字符 | \v | 匹配垂直制表符 |
# Pattern and Matcher in Java
Java正则表达式主要涉及 Pattern
和 Matcher
两个核心类,它们都在 java.util.regex
包中。
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class PatternDemo {
public static void demonstratePattern() {
// 1. 编译正则表达式
Pattern pattern = Pattern.compile("\\w+");
// 2. 编译时设置标志
Pattern patternWithFlags = Pattern.compile("\\w+",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
// 3. 创建Matcher对象
Matcher matcher = pattern.matcher("test string");
// 4. 分割字符串
String[] parts = pattern.split("hello,world");
// 5. 快速匹配
boolean isMatch = Pattern.matches("\\d+", "123");
// 6. 获取正则表达式
String regex = pattern.pattern();
// 7. 获取编译标志
int flags = pattern.flags();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MatcherDemo {
public static void demonstrateMatcher() {
Pattern pattern = Pattern.compile("\\w+");
String text = "Hello World";
Matcher matcher = pattern.matcher(text);
// 1. 查找匹配
boolean found = matcher.find(); // 查找下一个匹配
boolean matches = matcher.matches(); // 整个字符串是否匹配
boolean lookingAt = matcher.lookingAt(); // 从开始处查找匹配
// 2. 获取匹配信息
int start = matcher.start(); // 匹配的起始位置
int end = matcher.end(); // 匹配的结束位置
String group = matcher.group(); // 匹配的内容
// 3. 替换操作
String replaced = matcher.replaceAll("replacement");
String replacedFirst = matcher.replaceFirst("replacement");
// 4. 重置操作
matcher.reset(); // 重置匹配器
matcher.reset("new text"); // 重置并更改文本
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Pattern
类核心方法:
compile(String regex)
: 编译正则表达式compile(String regex, int flags)
: 带标志的编译matcher(CharSequence input)
: 创建Matcher
对象split(CharSequence input)
: 分割字符串matches(String regex, CharSequence input)
: 静态匹配方法pattern()
: 返回正则表达式字符串flags()
: 返回编译标志
Matcher
类核心方法:
find()
: 查找下一个匹配matches()
: 整个字符串匹配lookingAt()
: 从开始处匹配group()
: 返回匹配的字符串group(int group)
: 返回指定分组start()
: 返回匹配的起始位置end()
: 返回匹配的结束位置replaceAll(String replacement)
: 替换所有匹配replaceFirst(String replacement)
: 替换第一个匹配reset()
: 重置匹配器appendReplacement()
: 追加替换内容appendTail()
: 追加剩余内容
在Java中,正则表达式中实现不区分大小写匹配的示例:
// 使用 (?i) 标记
String regex = "(?i)hello";
// 或者使用 Pattern.CASE_INSENSITIVE 标志
Pattern pattern = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
1
2
3
4
5
2
3
4
5
部分模式不区分大小写:
// (?i)abc 表示abc都不区分大小写
// a(?i)bc 表示bc不区分大小写
// a((?i)b)c 表示只有b不区分大小写
String text = "UserName: John_Doe, EMAIL: John@example.com";
// 只有 email 部分不区分大小写
String pattern1 = "Username: \\w+, (?i)email: [\\w@.]+";
Pattern.matches(pattern1, text); // true
// 也可以用 (?-i) 关闭不区分大小写
String pattern2 = "(?i)Username: \\w+, email: (?-i)[a-z@.]+";
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
注意事项:
(?i)
可以放在整个正则表达式的开始处,也可以放在需要忽略大小写的部分前面可以使用
(?-i)
来关闭不区分大小写的效果