这篇博文是我在看完http://blog.csdn.net/luoweifu/article/details/42613533 的基础下 对一些模糊的地方进行实践而总结的案例,所以我假设所有人都看玩了这篇博文
java部分的实践
1 group
import java.util.regex.Matcher; import java.util.regex.Pattern; public class TestPattern { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Pattern p=Pattern.compile("([a-z]+)(\\d+(\\w+))"); Matcher m=p.matcher("aaa2223bb-aaa2223cc"); m.find(); //匹配aaa2223 m.find(); System.out.println(m.group(3)); System.out.println(m.groupCount()); //返回2,因为有2组 m.start(1); //返回0 返回第一组匹配到的子字符串在字符串中的索引号 System.out.println(m.start(2)); //返回3 m.end(1); //返回3 返回第一组匹配到的子字符串的最后一个字符在字符串中的索引位置. m.end(2); //返回7 m.group(1); //返回aaa,返回第一组匹配到的子字符串 m.group(2); //返回2223,返回第二组匹配到的子字符串 for(int i = 0 ; i <= m.groupCount();i++){ System.out.println(m.group(i)); } } }
在正则表达式里面存在一个捕获组的概念,你写的正则的表达式是一个最大的捕获组,用来匹配你预期的对象,在正则表达式里面用() 小括号来界定一个子捕获组
子捕获组可以针对特定目的加以使用,比如我们可以匹配 ${valuename}字符串 根据valuename来替换这一字符串内容,这个将在我最后的案例中使用
matcher.group() 返回的是 group(0) 也就是完全匹配的捕获组 传进group的index表示子捕获组的编号,编号根据捕获组出现的位置从左到右递增,子捕获组可以嵌套
E.G. (\w(\d)) 这就包含了2个捕获组 在捕获组数组中的次序是 \w\d \d
另外存在一个有意思的案例 (\w)+ 这样的不确定匹配, 你肯定想着返回能匹配的一长串字符,但是实际上是返回了匹配字符串能满足捕获组要求的最后一个子捕获组
E.G 222222 regex: (\d)+ 捕获完的结果是 2
2 string,replaceAll(pattern,string)
public class ReplaceAll { public static void main(String[] args){ String str = "$ \\\\=$ \\=$9\\"; System.out.println(str); /* * string.replaceAll()中的特殊字符 $ 与 \ * * 由于 $ 字符在作为替换内容时,是一个特殊字符,指反向引用前面的分组内容,所以把 * 某字符替换成 $ 字符时,因该在前面加上转义字符 \。 * \ 字符就不用说了,本身就是转义字符,但为什么在作为替换内容时要使用四个 \ 字符 * ,这里又不是用在正则表达式里?这就是因为 \ 字符在作为替换内容里也是一个特殊字 * 符,它用来将前面讲的 $ 字符进行转换的,所以也为特殊字符。以下是replaceAll的 * 源码片断,从源码就可以看出 \$ 是两个特殊字符 * * if (nextChar == '\\') { * cursor++; * nextChar = replacement.charAt(cursor); * result.append(nextChar); * cursor++; * } else if (nextChar == '$') { * // Skip past $ * cursor++; * ... * }else { * result.append(nextChar); * cursor++; * } */ //这里的$1表示第一个捕获组 System.out.println(str.replaceAll("\\$(\\w)\\\\", "\\\\$1\\$"));// \ $ System.out.println("\\$(\\W)\\\\"); System.out.println("\\\\$1\\$"); } }
string 的replaceall方法内部也是采用正则来实现的 所以规则和正则相同, 在替换的时候要注意$在替换字符串中代表着对原字符串指定捕获组的引用 $1 表示group(1)
属于如果我们想替换$进去 那么 我们就必须转义 替换\$进去,应为 \在string中是转义字符串 写成替换字符的时候还需要转一次 也就是写成"\\$"
另外在replace匹配的时候$也得写成 "\\$" 因为$也代表这结尾限定符,如果不转义 最后结尾限定符也会与他匹配
在这里我们可以总结一些 假如我们需要利用把一个字符串中某些字符子串替换另外一串字符串 步骤如下
1确定最后的结果显示 E.G. \$
2确定经过转义在结果字符串中的形式 E.G. \\$
3检查替换字符串是是否存在特殊字符和转化之后的形式 E.G \\\$
4确定经过转义结果字符串的含义 E.G. \\\\\\$
3matcher.appendReplacement(sb, String); matcher.appendTail(sb);
sb的定义是stringbuffer
matcher.appendReplacement(sb, String)
做的事情分2步 1 将当前指向的group替换成String
2将从上个捕获组末尾下一位到 替换完的字符串 的所有字符写入sb中
import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexExam { public static void main(String args[]) { HashMap data = new HashMap(); String template = "尊敬的客户${customerName}你好!本次消费金额${amount}," + "您帐户${accountNumber}上的余额为${balance},欢迎下次光临!"; data.put("customerName", "刘明"); data.put("accountNumber", "888888888"); data.put("balance", "$1000000.00"); data.put("amount", "$1000.00"); try { System.out.println(composeMessage(template, data)); } catch (Exception e) { e.printStackTrace(); } } public static String composeMessage(String template, Map data) throws Exception { String regex = "\\$\\{(.+?)\\}"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(template); /* * sb用来存储替换过的内容,它会把多次处理过的字符串按源字符串序 * 存储起来。 */ StringBuffer sb = new StringBuffer(); while (matcher.find()) { String name = matcher.group(1);//键名 String value = (String) data.get(name);//键值 if (value == null) { value = ""; } else { /* * 由于$出现在replacement中时,表示对捕获组的反向引用,所以要对上面替换内容 * 中的 $ 进行替换,让它们变成 "\$1000.00" 或 "\$1000000000.00" ,这样 * 在下面使用 matcher.appendReplacement(sb, value) 进行替换时就不会把 * $1 看成是对组的反向引用了,否则会使用子匹配项值amount 或 balance替换 $1 * ,最后会得到错误结果: * * 尊敬的客户刘明你好!本次消费金额amount000.00,您帐户888888888上的余额 * 为balance000000.00,欢迎下次光临! */ //My annotion //这里替换字符串产生的原因 需要进去的字符为\$ 所以应该替换进去的为 \\$ //而因为在替换字符中$代表对group捕获组的反向调用 所以替换进去的字符串改为 \\\$ (替换换成即为\\$ 显示效果为\$) //因为\在字符串中有特殊含义 所以应该转义 最后结果为\\\\\\$ value = value.replaceAll("\\$", "\\\\\\$"); System.out.println("value=" + value); } /* * 经过上面的替换操作,现在的 value 中含有 $ 特殊字符的内容被换成了"\$1000.00" * 或 "\$1000000000.00" 了,最后得到下正确的结果: * * 尊敬的客户刘明你好!本次消费金额$1000.00,您帐户888888888上的 * 余额为$1000000.00,欢迎下次光临! * * 另外,我们在这里使用Matcher对象的appendReplacement()方法来进行替换操作,而 * 不是使用String对象的replaceAll()或replaceFirst()方法来进行替换操作,因为 * 它们都能只能进行一次性简单的替换操作,而且只能替换成一样的内容,而这里则是要求每 * 一个匹配式的替换值都不同,所以就只能在循环里使用appendReplacement方式来进行逐 * 个替换了。 */ matcher.appendReplacement(sb, value); System.out.println("sb = " + sb.toString()); } //最后还得要把尾串接到已替换的内容后面去,这里尾串为“,欢迎下次光临!” matcher.appendTail(sb); return sb.toString(); } }
matcher.appendTail(sb); 响应就更好理解了 把最后一个捕获组的后一位字符到结尾的字符写入sb中
js部分的实践
<html> <head> <script type="text/javascript"> function PrintEmail(text) { //匹配的模式 var reg = RegExp("([\\w-.]+)@([\\w-])+((\.[\\w-]{2,3}){1,2})", "g"); var result; //保存结果 var arr = reg.exec(text); //循环输出结果 for(var i=0;i<arr.length;i++){ document.write(arr[i]+"<br>"); } while ((result = reg.exec(text)) != null) { document.write(result[0] + "<br/>" + result.index); document.write("<br/><br/>"); } } var text = "张三 Zhang.San@163.com; 李四 Li_si@126.com;王五 WangWu@gmail.com.cn" ; PrintEmail(text); windows.onload=PrintEmail(text); </script> </head> <body> </body> </html>
原理和js一致 只需要说的是 exec 返回的是一个捕获组数组 相当于java中 将一次匹配得到的所有group组成的一个数组
上面的测试代码都是从原来文章或者网上案例中拉 的 经过一点小修改,如果有冒犯 请多包涵