在 Java 中使用正则表达式进行后向引用($1,$2...)

自 JDK1.4 引入正则表达式的支持可称得上是次大改变,可 Java 的正则表达式的能力还是很弱,别说和 Perl 比了,就是和 C# 和 JavaScript 的正则表达式比较来也逊色不少,不过现在 JVM 上有其他语言对正则表达式有所增强,像 Groovy, jRuby 和 Scala。


[修正一下] 第一句话的说法是有误的,其实 JDK 本身的正则表达式就支持替换时用 $1, $2 那样的后向分组引用,例如:
String s = "abc def".replaceAll("(\\w+)\\s+(\\w+)", "$2 $1");  //s 就是  "def abc",replaceFirst 也可以用 $1, $2 的替换。

比如在 Java 中要实现正则表达式的分组,后向引用的方式进行替换挺复杂的,像 JavaScript 完成两个分组的调换:
1<script>
2    var src = "abc def";
3    var des = src.replace(/(\w+)\s+(\w+)/, "$2 $1");
4    document.write(des);
5    //输出为: def abc
6</script>

在 Java 中可得用上 Pattern, Matcher,还要 find()/group() 等操作,于是我就会考虑在 Java 中完成类似的功能有没有曲线的方法,有的。你可以调用 JVM 上其他语言的功能,我这里用列了两种实现方式

JDK1.6 起可借助 ScriptEngineManager 使用 JavaScript 相应的函数,除此之外还可用第三方的库 JRegex,具体实现,请参见如下代码,还带了测试用例:
 1package cc.unmi.utils;
 2import javax.script.Invocable;
 3import javax.script.ScriptEngine;
 4import javax.script.ScriptEngineManager;
 5
 6import jregex.Pattern;
 7import jregex.Replacer;
 8
 9public class StringUtils {
10    public static String replaceStringByJS(String src, String jsRegex, String replacement) {
11        ScriptEngineManager manager = new ScriptEngineManager();
12        ScriptEngine engine = manager.getEngineByName("JavaScript");
13        String script =
14                "function rep(target, regex, replacement){\n"
15              + "    var patt = new RegExp(regex,'g');\n"
16              + "    return target.replace(patt, replacement);\n"
17              + "}";
18
19        try {
20            engine.eval(script);
21            Invocable inv = (Invocable) engine;
22            String result = (String) inv.invokeFunction("rep", src, jsRegex,
23                    replacement);
24            return result;
25        } catch (Exception e) {
26            throw new RuntimeException(e);
27        }
28    }
29
30    public static String replaceStringByJRegex(String src, String regex, String replacement) {
31        Pattern pattern = new Pattern(regex);
32        Replacer replacer = pattern.replacer(replacement);
33        String result = replacer.replace(src);
34        return result;
35    }
36
37    public static void main(String[] args) {
38        String link="<link url=\"http://unmi.cc\" >\"Home\"</link>"
39                +"<link url=\"http://unmi.cc/tag/java\" >\"Java\"</link>";
40        String jsString = StringUtils.replaceStringByJS(link,
41                "<link\\s+url=\\\"(.+?)\\\".[^/]*?>\\\"(.+?)\\\"</link>", "<a href=\"$1\">$2</a>");
42        System.out.println(jsString);
43
44        String jregexString = StringUtils.replaceStringByJRegex(link,
45                "<link\\s+url=\\\"(.+?)\\\".[^/]*?>\\\"(.+?)\\\"</link>", "<a href=\"$1\">$2</a>");
46        System.out.println(jregexString);
47    }
48    
49    /*
50     * 程序输出
51     * <a href="http://unmi.cc">Home</a><a href="http://unmi.cc/tag/java">Java</a>
52     * <a href="http://unmi.cc">Home</a><a href="http://unmi.cc/tag/java">Java</a>
53     */
54}

起初我是用的第一种方法,后来找到了第二种方式,感觉用 JRegex 更优雅些。 永久链接 https://yanbin.blog/java-regex-replace-string/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。