正则表达式的基础用法
最近专门学习了一下正则表达式在java中的用法,主要还是看了尚学堂马士兵的视频教程,有一个专题是讲正则表达式的,在这里就把自己的学习笔记给帖一下。
那么,正则表达式的好处就不用多说了,用途也很广泛,比如ip地址匹配,邮箱之类的匹配。
在java中,关于正则表达式的类有两个:Pattern和Matcher,常用的用法也有两种:
Pattern p = Pattern.compile("^[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+"); Matcher m = p.matcher("abcdef@qq.com"); System.out.println(m.matches());
第二种是直接通过String的方法:
"abcdef@qq.com".matches("^[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+");
两种方法的区别是,第一种方式是以Pattern的格式编译后再进行的匹配,效率会比第二种方式高,特别是在同一种pattern进行多次匹配的情况下。
下面是一些常用的字符用法:
*//0个或者多个 +//1个或者多个 ?//1或者0个 .//任何字符 []//代表一个字符 {}//数量 ^//在[]内部,表非;在[]外部,表示开头 还有\s,\S,\d,\D,\w,\W等,具体的看api文档里的java.util.regex.Pattern的说明,里面讲的比较详细。 这里要提醒的是,要注意正则表达式和java中的转义字符
下面是一些正则表达式的常用用法,我在代码里已经注释的比较详细了,就不多说了
View Code
//Matcher中的几个比较重要的方法 public static void testSomeMethod(){ //在这里我用!表示匹配器当前匹配时指针所在的位置 Pattern pattern = Pattern.compile("\\d{3,5}"); String s = "123-2345-34567-89"; Matcher match = pattern.matcher(s); p(match.matches());//这个方法会匹配整个字符串,而当匹配到第一个“-”的时候就返回false //此时的指针情况是"123-!2345-34567-89" match.reset();//重新设定匹配指针的位置 //此时的指针情况是"!123-2345-34567-89" p(match.find());//true; 此时的指针情况是"123!-2345-34567-89" p(match.start()+"~"+match.end());//0-3 start()输出匹配的子字符串的第一个字符的位置 //end()为最后一个字符的下一个字符的位置 p(match.find());//true; 此时的指针情况是"123-2345!-34567-89" p(match.start()+"~"+match.end());//4-8 p(match.find());//true; 此时的指针情况是"123-2345-34567!-89" p(match.start()+"~"+match.end());//9-14 p(match.find());//false; 此时的指针情况是"123-234-34567!-89" p(match.start()+"~"+match.end());//报错 ,必须是能找到匹配的子字符串,才能调用start()和end() //如果将match.reset()注释,则是true,true,false,false. //因为调用matches()方法后,指针已经不在最开始的位置了,所以后面只有两个符合的子字符串,即2345,34567. p(match.lookingAt()); p(match.lookingAt()); p(match.lookingAt()); p(match.lookingAt()); //都是true,每次调用lookingAt()方法,都会从头开始查,即在这里,每次都是从123开始 /* * 总结: * matches()是每次都将匹配整个字符串,如果遇到不匹配的,则马上return false;匹配指针停在当前的位置 * find()方法是查找字符串中的是否有子字符串符合pattern,指针停留在上一次成功匹配后的下一个字符 * lookingAt()也是查找否是包含符合的子字符串,但是每次都是从字符串的开头开始查 * * 注意:这里的指针是为了更好的理解其匹配过程,实际上不一定是这样的(应该不是...) */ } //使用正则表达replace的一些方法 public static void testReplace(){ Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE); Matcher m = p.matcher("JAVA,java,Java,JAvA,jAVA,jAvA,addjAva,dddjavA,尾巴字符串"); // p(m.replaceAll("java"));//将m中所以匹配p模式的所有子字符串都转换成"java",并重置了matcher //output:java,java,java,java,java,java,addjava,dddjava,尾巴字符串 /* * replaceAll()不灵活, * 比如要吧所有的匹配的字符串中,奇数的改成java,偶数的改成JAVA,可以用下面的方法 */ StringBuffer buf = new StringBuffer(); int num = 0; while(m.find()){ num++; if(num%2!=0){ //从上一次匹配子字符串后的end()位置开始,到这次匹配的子字符串end()-1(即整个子字符串的最后一个字符的position) //简单来书就是讲previous end()~ current end()-1之间的String append到buf中 //如果往后没有匹配的子字符串,则将当前的matcher的position设定为最后一个匹配成功的end() m.appendReplacement(buf, "java"); }else{ m.appendReplacement(buf, "JAVA"); } } p(buf);//output:java,JAVA,java,JAVA,java,JAVA,addjava,dddJAVA m.appendTail(buf);//将剩下的非匹配字符append到buf中 p(buf);//output: java,JAVA,java,JAVA,java,JAVA,addjava,dddJAVA,尾巴字符串 } //正则表达式的分组 public static void testGroup(){ /*Pattern p = Pattern.compile("\\d{3,5}[a-z]{2}"); Matcher m = p.matcher("12aa-234bb-3456cc-45678dd-5678"); while(m.find()){ p(m.group()); }*/ /*output: 234bb 3456cc 45678dd*/ Pattern p = Pattern.compile("(\\d{3,5})([a-z]{2})"); Matcher m = p.matcher("12aa-234bb-3456cc-45678dd-5678"); int count = 0; p("count = "+(count = m.groupCount()));//output:2 0组表示整个模式 for(int i=0;i<=count;i++){ p("----count="+i+"----"); m.reset(); while(m.find()){ p(m.group(i)); } } /*output: * count = 2 ----count=0---- 234bb 3456cc 45678dd ----count=1---- 234 3456 45678 ----count=2---- bb cc dd * */ /* * 总结: * 1.查看有多少组,可以输小括号的左边"(",有几个"("就有几组,"("是第几个,那么该()内相关结果就在第几组 * 如上面的例子,(\\d{3,5})([a-z]{2}),数字就是第一个()内,在group(1);字符在group(2) * 注意,这里要考虑到第0组表示整个表达式的匹配结果,有可能会出现内嵌的(),比如(...(...)),还是按照上面的方法算 * * 经常用到分组的方法,比如获取一个网页页面的所有email的用户名称,而不需要其他的字符,就可以使用分组获取用户名 */ } /* * 按照jdk文档,quantifiers分为三种:Greedy, Reluctant ,Possessive * 先看看三种方式的写法区别后再看下面的例子 */ public static void testQuantifiers(){ /* * Greedy quantifiers 贪婪修饰符 (默认) * * 先一次性(贪婪的)“吞”进8个\w,看是否匹配,匹配则放回true; * 否则,“吐”出一个字符,再按照7个\w算,看是否匹配,匹配则返回true, * 否则... * 在这里到第七个就return true */ Pattern p1 = Pattern.compile("\\w{2,8}[0-9]"); Matcher m1 = p1.matcher("aaa8sss9"); if(m1.find()){ p(m1.start()+"-"+m1.end());//0-8 }else{ p("not match"); } /* * Reluctant quantifiers 贪婪修饰符 * * 先一次性(不情愿的)“吞”进2个\w,看是否匹配,匹配则放回true; * 否则,再“吞”一个字符,按照3个\w算,看是否匹配,匹配则返回true, * 否则... * 在这里到第3个就return true */ Pattern p2 = Pattern.compile("\\w{2,8}?[0-9]"); Matcher m2 = p2.matcher("aaa8sss9"); if(m2.find()){ p(m2.start()+"-"+m2.end());//0-4 }else{ p("not match"); } /* * Possessive quantifiers 贪婪修饰符 (很少用) * * 先一次性“吞”进8个\w,看是否匹配,匹配则返回true; * 否则返回false,不“吐”出来了(独占,possessive) * */ Pattern p3 = Pattern.compile("\\w{2,8}+[0-9]"); // Matcher m3 = p3.matcher("aaa8sss95"); Matcher m3 = p3.matcher("aaa8sss9"); if(m3.find()){ p(m3.start()+"-"+m3.end());//not match // p(m3.start()+"-"+m3.end());//0-9 }else{ p("not match"); } }
在这里再提两点比较特殊的情况:
Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE); //上面的pattern和下面的语句达到的效果是一样的 "jAvA".matches("(?i)(java)"); "\\".matches("\\\\");//匹配反斜杠
最后,推荐一篇关于正则表达式的文章,讲得非常详细:http://blog.csdn.net/allwefantasy/article/details/3136570
彪悍的人生,不需要解释