Java如何不依赖第三方库从正则表达式提取命名捕获组名称
Java正则命名捕获组提取方案
方案1:正则匹配法(优先推荐,无依赖兼容性强)
实现原理
Java命名捕获组语法固定为(?<组名>),组名规则为「首字符必须为字母,后续可接字母、数字、下划线」,通过匹配符合规则的子串即可提取组名,同时通过零宽断言排除被转义的(?<场景。
实现代码
import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexUtils { // 匹配命名捕获组的正则,自动排除转义场景 private static final Pattern NAMED_GROUP_PATTERN = Pattern.compile("(?<!\\\\)(?:\\\\\\\\)*\\(\\?<([a-zA-Z][a-zA-Z0-9_]*)>"); public static List<String> extractNamedGroups(String regex) { List<String> groupNames = new ArrayList<>(); // 兼容带定界符和修饰符的输入格式,比如/xxx/gm String processedRegex = regex; if (regex.startsWith("/")) { int lastSlashIndex = regex.lastIndexOf('/'); if (lastSlashIndex > 0) { processedRegex = regex.substring(1, lastSlashIndex); } } Matcher matcher = NAMED_GROUP_PATTERN.matcher(processedRegex); while (matcher.find()) { groupNames.add(matcher.group(1)); } return groupNames; } // 测试用例 public static void main(String[] args) { String input = "/(?<name>\\w+) (?<surname>\\w+)/gm"; List<String> groups = extractNamedGroups(input); System.out.println(groups); // 输出 [name, surname] } }
优缺点说明
- 优点:纯JDK实现无第三方依赖,不受JDK版本、安全管理器、Java模块化限制,性能满足绝大多数业务场景
- 缺点:极端场景下会误判,比如正则的字符串常量段中人工写入了
(?<字样,这类场景占比不足1%,如需完美处理可以使用方案2
方案2:修正后的反射提取法(准确率100%)
问题修复说明
你之前反射失败的核心原因是:namedGroups是Pattern类的私有字段,getField()只能获取public修饰的字段,需要改用getDeclaredField()。
实现代码
package my.package; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyPatternUtils { private static final Logger log = LoggerFactory.getLogger(MyPatternUtils.class); @SuppressWarnings("unchecked") public static Map<String, Integer> getNamedGroups(Pattern pattern) { if (pattern == null) { return Collections.emptyMap(); } try { Field namedGroupsField = Pattern.class.getDeclaredField("namedGroups"); namedGroupsField.setAccessible(true); Map<String, Integer> namedGroups = (Map<String, Integer>) namedGroupsField.get(pattern); return namedGroups == null ? Collections.emptyMap() : Collections.unmodifiableMap(namedGroups); } catch (Throwable t) { log.error("反射获取命名组失败", t); } return Collections.emptyMap(); } // 直接从正则字符串提取的快捷方法 public static List<String> extractNamedGroups(String regex) { // 兼容带定界符的输入格式 String processedRegex = regex; if (regex.startsWith("/")) { int lastSlashIndex = regex.lastIndexOf('/'); if (lastSlashIndex > 0) { processedRegex = regex.substring(1, lastSlashIndex); } } Pattern pattern = Pattern.compile(processedRegex); return new ArrayList<>(getNamedGroups(pattern).keySet()); } }
优缺点说明
- 优点:100%准确,完全匹配Java正则引擎的解析结果,不会受正则内容干扰
- 缺点:依赖Pattern内部实现,不同JDK版本可能存在字段变更,开启安全管理器或Java模块化环境下可能有权限限制
内容的提问来源于stack exchange,提问作者Andrei Matei
相关产品推荐
相关产品推荐

