- 自 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 更优雅些。