我有一个函数,它接受一个正则表达式和另一个字符串,并返回一个将正则表达式与任何输入相匹配的 lambda。我希望另一个字符串能够使用正则表达式中的匹配组,但我找不到在 Java 中执行此操作的方法。
最小示例:
public static Function<String, AbstractMap.SimpleEntry> process(String regex, String template){
return input -> {
Matcher m = Pattern.compile(regex).matcher(input);
if(!m.find()){
return null;
}
// Want something like:
// String key = m.expand(template);
// That *only* expands template and doesn't add anything else.
// **Doesn't work**
// m.replaceFirst/appendReplacement keep parts of the original input
String key = m.replaceFirst(template);
return Map.entry(key, input);
};
}
public static void main (String[] args) throws Exception {
String text = "https://www.myaddress.com?x=y&w=z&other=other&q=taco&temp=1";
Function<String, AbstractMap.SimpleEntry> func1 = process("myaddress.com.*[?&]q=(\\w+)", "$1");
Function<String, AbstractMap.SimpleEntry> func2 = process("myaddress.com.*[?&]q=(?<query>\\w+)", "query: ${query}");
System.out.println(func1.apply(text).getKey());
// Outputs "https://www.taco&temp=1" want "taco"
System.out.println(func2.apply(text).getKey());
// Outputs "https://www.query: taco&temp=1" want "query: taco"
}
此示例仅使用单个捕获组,但
regex
/template
可以是任何内容,我们应该一般支持它(例如,进程应将 $1 $4 ${mygroup}
作为兼容 template
的 regex
处理)。强迫用户匹配整个 URL 也是不可取的。
Expand
函数用于此,如何在 Java 中实现它而不需要重新实现 $
捕获组语法的解析?
我目前拥有的最佳解决方法就是在编译时将
.*
添加到正则表达式字符串中。
“...如何在Java中实现而不需要重新实现$捕获组语法的解析?...”
返回捕获值的唯一方法是通过 Pattern 和 Matcher 类。
或者,正如您提到的,附加
.*
。
“...我希望其他字符串能够使用正则表达式中的匹配组,但我找不到在Java中执行此操作的方法。...
// Outputs "https://www.taco&temp=1" want "taco"
实现模板语法并不困难。
Matcher#namedGroups 方法返回捕获组名称及其组编号的 Map。
for (int i = 1; i <= m.groupCount(); i++)
input = input.replaceAll("\\$" + i, m.group(i));
for (Map.Entry<String, Integer> e : m.namedGroups().entrySet())
input = input.replaceAll("\\$\\{" + e.getKey() + "}", m.group(e.getValue()));
这是完整的重构。
public static Function<String, String> process(String regex, String template){
return input -> {
Matcher m = Pattern.compile(regex).matcher(input);
if(!m.find()) return null;
String string = template;
for (int i = 1; i <= m.groupCount(); i++)
string = string.replaceAll("\\$" + i, m.group(i));
for (Map.Entry<String, Integer> e : m.namedGroups().entrySet())
string = string.replaceAll("\\$\\{" + e.getKey() + "}", m.group(e.getValue()));
return string;
};
}
public static void main (String[] args) throws Exception {
String text = "https://www.myaddress.com?x=y&w=z&other=other&q=taco&temp=1";
Function<String, String> func1 = process("myaddress.com.*[?&]q=(\\w+)", "$1");
Function<String, String> func2 = process("myaddress.com.*[?&]q=(?<query>\\w+)", "query: ${query}");
System.out.println(func1.apply(text));
// Outputs "https://www.taco&temp=1" want "taco"
System.out.println(func2.apply(text));
// Outputs "https://www.query: taco&temp=1" want "query: taco"
}
输出
taco
query: taco