获取java正则表达式中的组名
我试图接收一个模式和一个字符串,并返回一个组名->匹配结果的映射 例如:获取java正则表达式中的组名,java,regex,Java,Regex,我试图接收一个模式和一个字符串,并返回一个组名->匹配结果的映射 例如: (?<user>.*) (?*) 我想返回一个映射,其中包含“user”作为键,以及与之匹配的任何值 问题是,我似乎无法从Java正则表达式api获取组名。我只能通过名称或索引获得匹配的值。我没有组名列表,Pattern和Matcher似乎都没有公开这些信息。 我检查了它的来源,似乎信息就在那里——只是没有向用户公开 我尝试了Java的Java.util.regex和jregex。(而且,如果有人建议使用其
(?<user>.*)
(?*)
我想返回一个映射,其中包含“user”作为键,以及与之匹配的任何值
问题是,我似乎无法从Java正则表达式api获取组名。我只能通过名称或索引获得匹配的值。我没有组名列表,Pattern和Matcher似乎都没有公开这些信息。
我检查了它的来源,似乎信息就在那里——只是没有向用户公开
我尝试了Java的Java.util.regex和jregex。(而且,如果有人建议使用其他性能良好、受支持且支持此功能的库,则不必太在意)。Java中没有API来获取命名捕获组的名称。我认为这是一个缺失的特征 简单的解决方法是从模式中选择命名为捕获组的候选组,然后尝试从匹配中访问命名组。换句话说,在插入与整个模式匹配的字符串之前,您不知道命名捕获组的确切名称 捕获命名捕获组名称的
模式是\(\?
(基于派生)
(困难的方法是为regex实现一个解析器并获取捕获组的名称)
示例实现:
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;
}
}
}
import java.util.Scanner;
导入java.util.Set;
导入java.util.TreeSet;
导入java.util.Iterator;
导入java.util.regex.Pattern;
导入java.util.regex.Matcher;
导入java.util.regex.MatchResult;
类RegexTester{
公共静态void main(字符串参数[]){
扫描仪=新的扫描仪(System.in);
String regex=scanner.nextLine();
StringBuilder输入=新建StringBuilder();
while(scanner.hasNextLine()){
input.append(scanner.nextLine()).append('\n');
}
Set namedGroups=getNamedGroupCandidates(regex);
Pattern p=Pattern.compile(regex);
匹配器m=p.Matcher(输入);
int groupCount=m.groupCount();
int matchCount=0;
if(m.find()){
//删除无效组
迭代器i=namedGroups.Iterator();
while(i.hasNext()){
试一试{
m、 组(i.next());
}捕获(IllegalArgumentException e){
i、 删除();
}
}
匹配计数+=1;
System.out.println(“匹配”+匹配计数+”:”;
System.out.println(“=”+m.group()+“=”);
System.out.println();
打印匹配(m,namedGroups);
while(m.find()){
匹配计数+=1;
System.out.println(“匹配”+匹配计数+”:”;
System.out.println(“=”+m.group()+“=”);
System.out.println();
打印匹配(m,namedGroups);
}
}
}
私有静态void printMatches(Matcher Matcher,Set namedGroups){
for(字符串名称:namedGroups){
String matchedString=matcher.group(名称);
if(matchedString!=null){
System.out.println(名称+“=”+匹配字符串+“=”);
}否则{
System.out.println(name+“”);
}
}
System.out.println();
对于(int i=1;i
不过,这个实现有一个警告。它目前无法在模式下与regex一起工作。这是解决这个问题的第二个简单方法:我们将调用非公共方法namedGroups()
在Pattern类中获得一个映射
,该映射通过将组名映射到组号。这种方法的优点是,我们不需要包含与正则表达式匹配的字符串来查找精确命名的组
就我个人而言,我认为这不是什么优势,因为如果输入字符串中不存在与正则表达式匹配的正则表达式的命名组,那么了解这些组是没有用的
但是,请注意:
- 如果代码在具有安全限制的系统中运行,以拒绝访问非公共方法(无修改器、受保护和私有方法)的任何尝试,则此方法可能不适用
- 该代码仅适用于来自Oracle或OpenJDK的JRE
- 在未来的版本中,代码也可能会中断,因为我们正在调用一个非公共方法
- 通过反射调用函数也可能会对性能造成影响。(在这种情况下,性能影响主要来自反射开销,因为
namedGroups()
方法中没有太大的影响)。我不知道性能影响如何影响整体性能,所以请对您的系统进行测量
import java.util.Collections;
导入java.util.Map;
导入java.util.Scanner;
导入java.util.regex.Pattern;
导入java.lang.reflect.Method;
导入java.lang.reflect.InvocationTargetException;
类RegexTester{
公共静态void main(字符串参数[]){
扫描仪=新的扫描仪(System.in);
String regex=scanner.nextLine();
//字符串regex=“(?[a-z]*)[trick(?ha)]\\Q(?Q+E+)\\E(.*)(?\\w+);
Pattern p=Pattern.compile(regex);
文科硕士
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);
}
}
Pattern p = Pattern.compile("(?<user>.*)");
Matcher m = p.matcher("JohnDoe");
System.out.println(m.namedGroups()); // {user=JohnDoe}
<dependency>
<groupId>com.github.tony19</groupId>
<artifactId>named-regexp</artifactId>
<version>0.2.3</version>
</dependency>
final Field namedGroups = pattern.getClass().getDeclaredField("namedGroups");
namedGroups.setAccessible(true);
final Map<String, Integer> nameToGroupIndex = (Map<String, Integer>) namedGroups.get(pattern);
List<String> namedGroups = new ArrayList<String>();
{
String normalized = matcher.pattern().toString();
Matcher mG = Pattern.compile("\\(\\?<(.+?)>.*?\\)").matcher(normalized);
while (mG.find()) {
for (int i = 1; i <= mG.groupCount(); i++) {
namedGroups.add(mG.group(i));
}
}
}
Map<String, String> map = new HashMap<String, String>(matcher.groupCount());
namedGroups.stream().forEach(name -> {
if (matcher.start(name) > 0) {
map.put(name, matcher.group(name));
} else {
map.put(name, "");
}
});