正则表达式的捕获组(capture group)在Java中的使用

捕获组分类

  1. 普通捕获组(Expression)
  2. 命名捕获组(?<name>Expression)

普通捕获组

从正则表达式左侧开始,每出现一个左括号“(”记做一个分组,分组编号从1开始。0代表整个表达式。

对于时间字符串:2017-04-25,表达式如下

(\\d{4})-((\\d{2})-(\\d{2}))

有4个左括号,所以有4个分组

编号捕获组匹配
0(\d{4})-((\d{2})-(\d{2}))2017-04-25
1(\d{4})2017
2((\d{2})-(\d{2}))04-25
3(\d{2})04
4(\d{2})25


public static final String DATE_STRING = "2017-04-25";
public static final String P_COMM = "(\\d{4})-((\\d{2})-(\\d{2}))";

Pattern pattern = Pattern.compile(P_COMM);
Matcher matcher = pattern.matcher(DATE_STRING);
matcher.find();//必须要有这句
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\nmatcher.group(1) value:%s", matcher.group(1));
System.out.printf("\nmatcher.group(2) value:%s", matcher.group(2));
System.out.printf("\nmatcher.group(3) value:%s", matcher.group(3));
System.out.printf("\nmatcher.group(4) value:%s", matcher.group(4));

命名捕获组

每个以左括号开始的捕获组,都紧跟着“?”,而后才是正则表达式。

对于时间字符串:2017-04-25,表达式如下

(?<year>\\d{4})-(?<md>(?<month>\\d{2})-(?<date>\\d{2}))

有4个命名的捕获组,分别是

编号名称捕获组匹配
00(?\d{4})-(?(?\d{2})-(?\d{2}))2017-04-25
1year(?\d{4})-2017
2md(?(?\d{2})-(?\d{2}))04-25
3month(?\d{2})04
4date(?\d{2})25


命名的捕获组同样也可以使用编号获取相应值

public static final String P_NAMED = "(?<year>\\d{4})-(?<md>(?<month>\\d{2})-(?<date>\\d{2}))";
public static final String DATE_STRING = "2017-04-25";

Pattern pattern = Pattern.compile(P_NAMED);
Matcher matcher = pattern.matcher(DATE_STRING);
matcher.find();
System.out.printf("\n===========使用名称获取=============");
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\n matcher.group('year') value:%s", matcher.group("year"));
System.out.printf("\nmatcher.group('md') value:%s", matcher.group("md"));
System.out.printf("\nmatcher.group('month') value:%s", matcher.group("month"));
System.out.printf("\nmatcher.group('date') value:%s", matcher.group("date"));
matcher.reset();
System.out.printf("\n===========使用编号获取=============");
matcher.find();
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\nmatcher.group(1) value:%s", matcher.group(1));
System.out.printf("\nmatcher.group(2) value:%s", matcher.group(2));
System.out.printf("\nmatcher.group(3) value:%s", matcher.group(3));
System.out.printf("\nmatcher.group(4) value:%s", matcher.group(4));

PS:非捕获组

在左括号后紧跟“?:”,而后再加上正则表达式,构成非捕获组(?:Expression)。

对于时间字符串:2017-04-25,表达式如下

(?:\\d{4})-((\\d{2})-(\\d{2}))

这个正则表达式虽然有四个左括号,理论上有4个捕获组。但是第一组(?:\d{4}),其实是被忽略的。当使用matcher.group(4)时,系统会报错。

编号捕获组匹配
0(\d{4})-((\d{2})-(\d{2}))2017-04-25
1((\d{2})-(\d{2}))04-25
2(\d{2})04
3(\d{2})25


public static final String P_UNCAP = "(?:\\d{4})-((\\d{2})-(\\d{2}))";
public static final String DATE_STRING = "2017-04-25";

Pattern pattern = Pattern.compile(P_UNCAP);
Matcher matcher = pattern.matcher(DATE_STRING);
matcher.find();
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\nmatcher.group(1) value:%s", matcher.group(1));
System.out.printf("\nmatcher.group(2) value:%s", matcher.group(2));
System.out.printf("\nmatcher.group(3) value:%s", matcher.group(3));

// Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 4
System.out.printf("\nmatcher.group(4) value:%s", matcher.group(4));

总结

  1. 普通捕获组使用方便;
  2. 命名捕获组使用清晰;
  3. 非捕获组目前在项目中还没有用武之地。
### 捕获组Capture Groups)详解 捕获组正则表达式中用于**捕获子匹配内容**的语法,通过使用括号 `()` 包裹的部分会被单独记录,便于后续提取或操作。它是处理复杂文本匹配时最常用的功能之一 [^3]。 #### 提取子内容 捕获组允许从完整的匹配中提取特定的部分。例如,正则表达式 `(\d{4})-(\d{2})-(\d{2})` 可以匹配日期格式 `YYYY-MM-DD`,并分别捕获年、月、日三个部分: ```javascript const text = "2023-10-01"; const regex = /(\d{4})-(\d{2})-(\d{2})/; const match = text.match(regex); console.log(match); // 输出: [ // "2023-10-01", // 完整匹配 // "2023", // 第1捕获组(年) // "10", // 第2捕获组(月) // "01" // 第3捕获组(日) // ] ``` #### 索引编号 捕获组的编号从左到右按 `( ` 出现的顺序分配,从1开始。例如,在正则表达式 `/((\d{2}):(\d{2}))\s+(\d{2}:\d{2})/` 中,第一个完整的匹配是整个时间字符串,第二个捕获组是第一个时间部分,第三个是分钟,第四个是第二个时间字符串 。 #### 复用匹配 捕获组的内容可以在正则表达式中通过反向引用复用。例如,正则表达式 `(\w+)\s+\1` 可以匹配重复的单词,如 `hello hello`: ```javascript const text = "hello hello world"; const regex = /(\w+)\s+\1/; const match = text.match(regex); console.log(match); // 输出: ["hello hello", "hello"] ``` #### 命名捕获组(Named Capture Groups) ES2018 引入了命名捕获组功能,通过 `?<name>` 语法为捕获组命名,使得提取和引用更加直观。例如: ```javascript let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u; let str = '2015-01-02'.replace(reg, (matched, capture1, capture2, capture3, position, S, groups) => { let { day, month, year } = groups; return `${day}/${month}/${year}`; }); console.log(str); // 输出: "02/01/2015" ``` 命名捕获组通过 `groups` 属性访问,结构清晰,易于维护 [^4]。 #### 非捕获组(Non-Capturing Group) 非捕获组用于分组但不捕获匹配内容,语法为 `(?:...)`。例如,正则表达式 `(?:abc)+` 匹配一个或多个连续的 `abc`,但不会单独记录该组的内容 。 ```javascript const text = "abcabcabc"; const regex = /(?:abc)+/; const match = text.match(regex); console.log(match); // 输出: ["abcabcabc"] ``` #### 使用场景 - **数据提取**:从非结构化文本中提取特定格式的数据,如价格区间、尺寸等 [^2]。 - **格式验证**:验证输入是否符合特定格式,如邮箱、电话号码等 [^2]。 - **字符串替换**:在复杂替换场景中,使用捕获组进行动态替换 [^4]。 - **日志分析**:解析日志文件,提取关键信息如时间戳、日志级别、消息等 [^1]。 ###
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值