正则表达式的基础用法

最近专门学习了一下正则表达式在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

 

 

 

 

posted @ 2012-07-24 00:55  huanggz1008  阅读(396)  评论(0编辑  收藏  举报