Java Matcher类 replaceAll 捕获组使用及使用符号$引用捕获组
最近看了一段解析URL以判断支付方式是在线支付还是具体哪个网银或支付宝的代码。如下
private String[] getAction(String url){
String action = null;
String pluginid = null;
String pattern = "/(\\w+)_(\\w+)_(\\w+).html(.*)";
Pattern p = Pattern.compile(pattern, 2 | Pattern.DOTALL);
Matcher m = p.matcher(url);
if (m.find()) {
action = m.replaceAll("$2");
pluginid =m.replaceAll("$3");
return new String[]{action,pluginid};
}else{
return null;
}
}
里面的m.replaceAll("$2")和m.replaceAll("$3")一直没看没明白什么意思,在网上搜也没有找到很具体的。结合网上一些博客和自己查看Matcher JDK源码的理解为大家分享一下。
Java 正则表达式中的捕获组 Mathcer 类的捕获组相关方法
先来看看Matcher 类的捕获组及相关方法
如里要解析一个HTML标签<textare>里面的内容如:
<textarea class="textarea" id="testid">经历了千千万万个轮回,我们相互寻觅似曾相识却又擦肩而过,不要怀疑今生一见就为什么对你如此痴迷。</textarea>
中的“经历了千千万万个轮回,我们相互寻觅似曾相识却又擦肩而过,不要怀疑今生一见就为什么对你如此痴迷。”
private String getTestarea(String text){
Pattern p1=Pattern.compile("<textarea .*?>(.*?)</textarea>");
Matcher m1=p1.matcher("<textarea class=\"textarea\" id=\"testid\">经历了千千万万个轮回,我们相互寻觅似曾相识却又擦肩而过,不要怀疑今生一见就为什么对你如此痴迷。</textarea>");
String result=null;
if(m1.find()){
result=m1.group();
System.out.println(result);
result=m1.group(1);
System.out.println(result);
}
}
对应结果为:
<textarea class="textarea" id="testid">经历了千千万万个轮回,我们相互寻觅似曾相识却又擦肩而过,不要怀疑今生一见就为什么对你如此痴迷。</textarea>
经历了千千万万个轮回,我们相互寻觅似曾相识却又擦肩而过,不要怀疑今生一见就为什么对你如此痴迷。
可以看到使用用java 正则表达式的捕获组很容易的就得到了标签<textarea>中的内容
在模式串“<textarea .*?>(.*?)</textarea>” 中的(.*?)对应捕获组1,即m1.group(1),整一个匹配串对应捕获组0,即m1.group()
与m1.group(0)一至,如果有多少个模式串中有多少个()情况以上面的类似大家可能网上搜索一下。上面提到了Matcher类的方法这里顺便讲一下find和matchers方法的区别
Matcher类 find 和matchers方法的区别
find方法是从要匹配的字符串的下标为0的位子一直找到结尾,如果整个要匹配的字符全和模式串对应,则find后对应Matcher对象的end方法返回值为要匹配的字符的长度。见下面代码
Pattern p1=Pattern.compile("\\d+");
Matcher m1=p1.matcher("123456");
m1.find();
System.out.println(m1.start());//0
System.out.println(m1.end());//6
如果不是整个要匹配的字符串和模式对应结果,如下
Pattern p1=Pattern.compile("\\d+");
Matcher m1=p1.matcher("qq123ww123ee123");
m1.find();
System.out.println(m1.start());//2
System.out.println(m1.end());//5
m1.find();
System.out.println(m1.start());//7
System.out.println(m1.end());//10
而matchers方法是对整个匹配串与模式串进行比较,符合结果为true否则为false。
使用符号$对捕获组进行引用
回到我们开始看的例子
private String[] getAction(String url){
String action = null;
String pluginid = null;
String pattern = "/(\\w+)_(\\w+)_(\\w+).html(.*)";
Pattern p = Pattern.compile(pattern, 2 | Pattern.DOTALL);
Matcher m = p.matcher(url);
if (m.find()) {
action = m.replaceAll("$2");
pluginid =m.replaceAll("$3");
return new String[]{action,pluginid};
}else{
return null;
}
}
其实action = m.replaceAll("$2"),pluginid =m.replaceAll("$3")中的“$2”及“$3”是对捕获组的引用,假设现在getAction的实参为“/pay_to_deposit.html”。那么上面讲的捕获组group(2)等价于“to”,group(3)等价于"deposit"。实际上$3表示对捕获组group(3)的引用。下面大家可以结合JDK源码中Matcher类中 appendReplacement方法的说明的英文进行理解
The replacement string may contain references to subsequences captured during the previous match: Each occurrence of
$g will be replaced by the result of evaluating
(g). The first number after the
group
$ is always treated as part of the group reference. Subsequent numbers are incorporated into g if they would form a legal group reference. Only the numerals ‘0‘ through ‘9‘ are considered as potential components of the group reference. If the second
group matched the string "foo", for example, then passing the replacement string
"$2bar" would cause "foobar" to be appended to the string buffer. A dollar sign ($) may be included as a literal in the replacement string by preceding it with a backslash (\$).
Matcher类中replaceAll方法调用了appendReplacement方法。从上面可以知道当我们在替换字符中本身有$符号时要做特殊的处理。顺便提醒一下在JAVA的String类的replaceAll方法中处理有$和\的字符串时也要提前处理即要转义。