我有一个函数,它接受一个正则表达式和另一个字符串,并返回一个lambda,该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也是不可取的。
Golang为此提供了一个Expand
函数,如何在Java中实现它而不重新实现$
捕获组语法的解析?
我目前最好的解决方法是在编译正则表达式字符串时,将.*
前置并追加到正则表达式字符串。
2条答案
按热度按时间bgtovc5b1#
返回捕获值的唯一方法是通过 Pattern 和 Matcher 类。
或者,如您所提到的,使用附加的
.*
。实现模板语法并不困难。
Matcher#namedGroups 方法返回捕获组名称及其组编号的 Map。
这里是完整的重构因子。
输出
c7rzv4ha2#
用我的变通方法来解决我的问题,因为它似乎是最优雅的解决方案。
Java中目前还没有这样的方法;最好的解决方法是将匹配扩展到整个字符串。
根据您使用的Java's three match operations的不同,扩展匹配看起来有点不同:
matches
-这已经与完整字符串匹配;匹配将必然包括所有输入。lookingAt
-从输入开始匹配,将.*
附加到正则表达式中,以在match 1中包含完整的输入。find
-匹配输入中的任何子字符串,将 * 和 * 前缀.*
添加到正则表达式以匹配完整输入。然后,您可以将原始解决方案与
replaceFirst
一起使用,它将按预期工作。请注意,由于您将匹配扩展到整个输入,因此一旦这样做,任何匹配操作都等效于使用
matches
。1等价地,在这种情况下,您可以使用
appendReplacement
而不调用appendTail
,而不是扩展匹配。