捕获组和非捕获组
捕获组
捕获组,通过括号将正则表达式括起来,正则表达式匹配成功后,可以通过组号来获取相应的匹配内容。如:我们想获取数字中的整数部分和小数部分,可以用这样的正则表达式。
String regex = "(\\d+)\\.(\\d+)";
String content = "12.98";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("数字:" + matcher.group());
System.out.println("整数部分 : " + matcher.group(1));
System.out.println("小数部分 : " + matcher.group(2));
}
这里用Matcher 中的 group(1),可以获取整数部分,用group(2)可以获取小数部分,如果group()中不填数字,则默认获取整个匹配组,即整个数字。
这里,我们用序号来获取相应的捕获组,但其实也可能给每个捕获组命名,通过名称来获取捕获组。
String regex = "(?<one>\\d+)\\.(?<two>\\d+)"; //?<name>指定组名称
String content = "12.98";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("数字:" + matcher.group());
System.out.println("整数部分 : " + matcher.group("one"));
System.out.println("小数部分 : " + matcher.group("two"));
}
非捕获组
非捕获组,即不要获取括号里的内容。
问1:既然不要获取括号里的内容,那在正则表达式中不加括号不就可以吗?
正则表达式中的括号,不仅用来分组,有些场景下,不加括号并不能写出你想要的效果。
举个例子:String regex = "12(a|b)12";
这个正则表达式,匹配的是开头和结尾是“12”,中间字符是a或b,如果没有括号,那就成:
String regex = "12a|b12";
匹配的结果就是字符“12a”或“b12”。
问2:那如果加括号后,我不用group()获取分组,不也可以吗?
语法上没错,但用了括号来捕获字符串,则会占用一定的内存去记录这些捕获组,如果我们实际上不需要这些捕获组,那可以不让内存记录着,提高程序效率 。
非捕获组有以下几种情况:
- (?:) 非捕获组
- (?=) 肯定式向前查找
- (?!) 否定式向前查找
- (?<=) 肯定式向后查找
- (?<!) 否定式向后查找
用了非捕获组,如果再用group(int index) 去获取匹配的内容,则会报错。
(?:) 非捕获组
例子:获取abc或adc字样的字符串。
捕获组的例子如下:
String regex = "a(b|d)c";
String content = "adcdddd";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("用group(1)获取第一个括号的内容 :" + matcher.group(1));
}
如果我们并不需要获取括号里的内容,那可以把这个括号写成一个非捕获组,如下:
String regex = "a(?:b|d)c";
String content = "adcdddd";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("匹配到的内容 :" + matcher.group(1));
}
注意,运行此程序,会报以下错,表示并没有group1 这个组。这是因为我们用了非捕获组,括号里的内容就不会进行记录,用group(1)自然就获取不到。
(?=) 肯定式向前查找
这里所说的向前,是指字符串从左到右的方向。如,查找被<html> </html> 包围着的字符串。
我们可以先查询到字符串<html>,再向前查</html>。
String regex = "\\<html\\>(.*)(?=\\</html\\>)";
String content = "<html> hello world </html>";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("match : " + matcher.group(1));
} else {
System.out.println("not match ");
}
运行结果为: match : hello world
'?=.'的意思是断言;只匹配一个位置
比如,你想匹配一个“人”字,但是你只想匹配中国人的人字,不想匹配法国人的人;就可以用断言做;
例子:必须包含大小写字母和数字的组合,后面的{8,10}表示长度
Pattern pattern = Pattern.compile("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$");
Matcher matcher = pattern.matcher("1aA12BC1");
while (matcher.find()) {
System.out.println(matcher.group());
}
(?!) 否定式向前查找
跟肯定式向前查找相反,是查找前面没有特定字符串的内容。
比如,查找出现“Java” 字符串且后面没有出现“Python” 的字符串。
String regex = "Java(?!.*Python.*)";
String content = "Java and Python are both good languages";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("match");
} else {
System.out.println("not match ");
}
此程序运行的结果是:not match
如果把字符串换成:Java and C++ are both good languages,则运行结果是 : match。
(?<=) 肯定式向后查找
查找前面有一个数字的英文字符串。
String regex = "(?<=\\d)([a-z]+)";
String content = "abcd2def";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("match : " + matcher.group(1));
} else {
System.out.println("not match ");
}
运行结果为:
match : def
(?<!) 否定式向后查找
不以end结尾的字符串。
String regex = "(.*)(?<!end)$";
String content = "python language end";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("match : " + matcher.group(1));
} else {
System.out.println("not match ");
}
运行结果为:
not match
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!