在使用正则表达式在匹配文本时,除了可以通过表达式捕获命中的文本串外,还可以对捕获的文本串进行命名。尤其是在解析日志的场景中,经常会被用到。表达式如下:
\<(?<pri>\d+)\>(?<time>.*) (?<host>\S+) (?<detail>Log.*)
该表达式对文本串匹配后会有四个捕获组,它们依次分别被命名为pri, time, host以及detail。在Java语言目前提供的正则表达式相关的类中,没有公共方法可以枚举这些命名捕获。即没有方法可以像用捕获组的下标一样来遍历捕获组。这无疑为使用者带来了一定的麻烦。
不过,通过仔细翻看Pattern的代码实现。不难看到,其实Patter对象内部有一个包内可见方法“namedGroups”。该方法返回一个捕获组的名字与捕获组对应下标的Map对象。可以通过访问Map对象的Key集合获得所有捕获组的名字。然后枚举捕获组的名字获得每个捕获的值。
下面,我们利用Java的反射机制获得捕获组名字与索引映射的Map:
public Map<String, Integer> getNamedGroups(Pattern pattern) {
try {
Method namedGroup = ReflectionUtils.getMethod(Pattern.class,
"namedGroups");
namedGroup.setAccessible(true);
return (Map<String, Integer>) namedGroup.invoke(pattern);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
拿到捕获组的命名Map后,就可以根据程序需要进行后续的访问应用了。