正则表达式——捕获分组(capture group)(Java代码)

本文详细介绍了正则表达式的捕获组,包括普通捕获组、命名捕获组、普通捕获组与命名捕获组混用及非捕获组的概念和使用方式,并给出了Java和C#的不同处理规则。通过实例代码演示了如何在正则表达式中捕获和使用这些分组,帮助理解正则表达式中的分组机制。
摘要由CSDN通过智能技术生成

正则大神主页:https://blog.csdn.net/lxcnn?t=1

正则表达式入门教程:https://deerchao.cn/tutorials/regex/regex.htm#top

上述两个博客的文章都是以C#为基础写作的,在普通捕获组与命名捕获组的混用上,与Java有所不同

正则运行测试网址:https://regex101.com/

正则中,每个用于匹配字符的()都是一个子表达式,可以被捕获分组捕获到,从而在正则表达式内或表达式外进行引用。环视使用了(),但是它是用来匹配位置信息的,所以不会被捕获;还有就是使用(?:expression)来主动忽略分组。

更新
在正则表达式本身中使用分组,默认编号分组-\d{4}([:-])\d{2}\1\d{2};命名分组-\d{4}(?<d>[-:])\d{2}(\k<d>)\d{2}

普通捕获组

正则表达式中,普通捕获组是按照(即左括号出现的顺序进行分组。对类似“2016-01-06”格式的日期进行简单匹配并分组,暂不不考虑闰年等问题。

分组分组内容
分组0(\d{4})-(\d{2})-(\d{2})
分组1\d{4}
分组2\d{2}
分组3\d{2}

对于所有的正则表达式,捕获组0都是正则表达式匹配的全部内容,然后第一对括号内包含的匹配内容是捕获组1,第二对括号内是捕获组2,第三对括号内是捕获组3.

Java实例代码如下:

String str = "2016-01-06";
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(str);
if (matcher.find()){
    System.out.println(matcher.group(0));
    System.out.println(matcher.group(1));
    System.out.println(matcher.group(2));
    System.out.println(matcher.group(3));
}
// 结果如下:
// 2016-01-06
// 2016
// 01
// 06

命名捕获组

还是对日期进行正则匹配,表达式本身不变,改为使用命名捕获组组。命名捕获组与普通捕获组的区别在于,在()内添加捕获组的名字,方便后续使用。格式为:(?<name>expression)。name区分大小写。

分组分组内容
分组year\d{4}
分组month\d{2}
分组day\d{2}

通过在()内添加?<name>,对捕获组进行命名,从而更方便后续对匹配内容的使用。

Java实例代码如下:

String str = "2016-01-06";
Pattern pattern = Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
Matcher matcher = pattern.matcher(str);
if (matcher.find()){
    System.out.println(matcher.group("year"));
    System.out.println(matcher.group("month"));
    System.out.println(matcher.group("day"));
}
// 结果如下:
// 2016
// 01
// 06

普通捕获组与命名捕获组混用

当普通捕获组与命名捕获组混用时,各个语言的具体规则略有差异。

在Java中,不管此捕获组是否被命名,依旧按照普通捕获组的规则进行排序,然后被命名的分组同时也可以作为命名捕获组使用。

普通捕获组命名捕获组分组内容
分组0(\d{4})-(\d{2})-(\d{2})
分组1\d{4}
分组2分组month\d{2}
分组3\d{2}

Java实例代码如下:

String str = "2016-01-06";
Pattern pattern = Pattern.compile("(\\d{4})-(?<month>\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(str);
if (matcher.find()){
    System.out.println(matcher.group(0));
    System.out.println(matcher.group(1));
    System.out.println(matcher.group(2));
    System.out.println(matcher.group(3));
    System.out.println(matcher.group("month"));
}
// 结果如下:
// 2016-01-06
// 2016
// 01
// 06
// 01

通过上述代码可以看到,月份01既可以作为普通捕获组2使用,同时也可以作为命名捕获组month使用。

C#的普通捕获组与命名捕获组混用时的规则与Java不一致。在C#中,会先去除已被命名的捕获组,对剩余的所有捕获组按照普通捕获组的规则进行排序,然后再对命名捕获组进行排序,因此在C#中,所有命名捕获组的序号都会大于普通捕获组的序号。

在上述例子中,已被命名为month的捕获组,在C#中序号应该是分组3,而不是分组2,分组2应该是用于匹配日期的子表达式。

C#普通捕获与命名捕获混用官方规则

Java普通捕获与命名捕获混用官方规则

非捕获组

在正则中,可以选择忽略某些捕获组,不将它们列入分组捕获排序中,从而更方便的获取我们想要匹配的内容。子表达式中增加?:,会被正则引擎忽略,不被计入捕获组中。(?:expression)这种格式的子表达式被称为非捕获组。

普通捕获组非捕获组分组内容
分组0(\d{4})-(\d{2})-(\d{2})
分组1\d{4}
非捕获组?:\d{2}
分组2\d{2}

Java实例代码如下:

String str = "2016-01-06";
Pattern pattern = Pattern.compile("(\\d{4})-(?:\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(str);
if (matcher.find()){
    System.out.println(matcher.group(0));
    System.out.println(matcher.group(1));
    System.out.println(matcher.group(2));
    System.out.println(matcher.group(3));
}
// 结果如下:
// 2016-01-06
// 2016
// 06
// Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 3

通过代码可以看到,匹配月份的子表达式被正则引擎忽略,并没有计入捕获组的排序中。其他子表达式依旧按照正常的分组排序规则进行排序,匹配日期的子表达式作为分组2被统计,导致缺少分组3,在获取时抛异常。

总结

正则表达式的捕获组内容包括有普通捕获组,命名捕获组,普通捕获组与命名捕获组混用,非捕获组。

上一篇:贪婪、非贪婪与占有模式
下一篇:反向引用

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值