在 Java 中扩展正则表达式子组匹配

问题描述 投票:0回答:1

我有一个函数,它接受一个正则表达式和另一个字符串,并返回一个将正则表达式与任何输入相匹配的 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 中实现它而不需要重新实现
$
捕获组语法的解析?

我目前拥有的最佳解决方法就是在编译时将

.*
添加到正则表达式字符串中。

java regex regex-group
1个回答
0
投票

“...如何在Java中实现而不需要重新实现$捕获组语法的解析?...”

返回捕获值的唯一方法是通过 PatternMatcher 类。
或者,正如您提到的,附加

.*

“...我希望其他字符串能够使用正则表达式中的匹配组,但我找不到在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
© www.soinside.com 2019 - 2024. All rights reserved.