我正在尝试接收模式和字符串并返回组名称的地图 - >匹配结果.
例:
(?<user>.*)
Run Code Online (Sandbox Code Playgroud)
我想返回一个包含"user"作为键的映射以及它匹配的值作为其值.
问题是我似乎无法从Java regex api获取组名.我只能按名称或索引获取匹配的值.我没有组名列表,Pattern和Matcher似乎都没有公开这些信息.我检查了它的来源,似乎信息就在那里 - 它只是没有暴露给用户.
我尝试了Java的java.util.regex和jregex.(并且不关心是否有人建议任何其他库,这些库是良好的,受支持的并且具有支持此功能的高性能).
nha*_*tdh 39
Java中没有API来获取指定捕获组的名称.我认为这是一个缺失的功能.
最简单的方法是从模式中挑选候选命名捕获组,然后尝试从匹配中访问命名组.换句话说,在插入与整个模式匹配的字符串之前,您不知道命名捕获组的确切名称.
该Pattern捕捉名为捕获组的名称是\(\?<([a-zA-Z][a-zA-Z0-9]*)>(根据派生Pattern类的文档).
(困难的方法是为正则表达式实现解析器并获取捕获组的名称).
示例实现:
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;
import java.util.Iterator;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.MatchResult;
class RegexTester {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
String regex = scanner.nextLine();
StringBuilder input = new StringBuilder();
while (scanner.hasNextLine()) {
input.append(scanner.nextLine()).append('\n');
}
Set<String> namedGroups = getNamedGroupCandidates(regex);
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
int groupCount = m.groupCount();
int matchCount = 0;
if (m.find()) {
// Remove invalid groups
Iterator<String> i = namedGroups.iterator();
while (i.hasNext()) {
try {
m.group(i.next());
} catch (IllegalArgumentException e) {
i.remove();
}
}
matchCount += 1;
System.out.println("Match " + matchCount + ":");
System.out.println("=" + m.group() + "=");
System.out.println();
printMatches(m, namedGroups);
while (m.find()) {
matchCount += 1;
System.out.println("Match " + matchCount + ":");
System.out.println("=" + m.group() + "=");
System.out.println();
printMatches(m, namedGroups);
}
}
}
private static void printMatches(Matcher matcher, Set<String> namedGroups) {
for (String name: namedGroups) {
String matchedString = matcher.group(name);
if (matchedString != null) {
System.out.println(name + "=" + matchedString + "=");
} else {
System.out.println(name + "_");
}
}
System.out.println();
for (int i = 1; i < matcher.groupCount(); i++) {
String matchedString = matcher.group(i);
if (matchedString != null) {
System.out.println(i + "=" + matchedString + "=");
} else {
System.out.println(i + "_");
}
}
System.out.println();
}
private static Set<String> getNamedGroupCandidates(String regex) {
Set<String> namedGroups = new TreeSet<String>();
Matcher m = Pattern.compile("\\(\\?<([a-zA-Z][a-zA-Z0-9]*)>").matcher(regex);
while (m.find()) {
namedGroups.add(m.group(1));
}
return namedGroups;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这个实现有一个警告.它目前无法在Pattern.COMMENTS模式下使用正则表达式.
nha*_*tdh 16
这是解决该问题的第二种简单方法:我们将namedGroups()在Pattern类中调用非公共方法,以Map<String, Integer>通过Java Reflection API获取将组名映射到组号的方法.这种方法的优点是我们不需要包含与正则表达式匹配的字符串来查找确切命名的组.
就个人而言,我认为它没有多大优势,因为知道正则表达式的命名组是无用的,其中输入字符串中不存在与正则表达式的匹配.
但请注意以下缺点:
namedGroups()).我不知道性能影响如何影响整体性能,所以请在您的系统上进行测量.import java.util.Collections;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Pattern;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
class RegexTester {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
String regex = scanner.nextLine();
// String regex = "(?<group>[a-z]*)[trick(?<nothing>ha)]\\Q(?<quoted>Q+E+)\\E(.*)(?<Another6group>\\w+)";
Pattern p = Pattern.compile(regex);
Map<String, Integer> namedGroups = null;
try {
namedGroups = getNamedGroups(p);
} catch (Exception e) {
// Just an example here. You need to handle the Exception properly
e.printStackTrace();
}
System.out.println(namedGroups);
}
@SuppressWarnings("unchecked")
private static Map<String, Integer> getNamedGroups(Pattern regex)
throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
Method namedGroupsMethod = Pattern.class.getDeclaredMethod("namedGroups");
namedGroupsMethod.setAccessible(true);
Map<String, Integer> namedGroups = null;
namedGroups = (Map<String, Integer>) namedGroupsMethod.invoke(regex);
if (namedGroups == null) {
throw new InternalError();
}
return Collections.unmodifiableMap(namedGroups);
}
}
Run Code Online (Sandbox Code Playgroud)
您想使用小的name-regexp库。它是一个瘦包装器java.util.regex,为 Java 5 或 6 用户提供命名捕获组支持。
Pattern p = Pattern.compile("(?<user>.*)");
Matcher m = p.matcher("JohnDoe");
System.out.println(m.namedGroups()); // {user=JohnDoe}
Run Code Online (Sandbox Code Playgroud)
<dependency>
<groupId>com.github.tony19</groupId>
<artifactId>named-regexp</artifactId>
<version>0.2.3</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
参考: