• 尚学堂-马士兵-专题-正则表达式


    一、最简单的正则表达式

    • String类的一个方法matches。
    package com.string;
    
    public class RegexTest {
    
        public static void main(String[] args) {
            /*
             * 最简单的正则表达式
             * 这里使用的是String类的matches方法.
             * 这个方法是比较字符是否匹配
             * .表示的时任意一个字符
             */
            System.out.println("abc".matches("..."));
        }
    }

    正则表达式是处理字符串的。 其实更确切的说,正则表达式是处理字符的。 就拿上面的例子来说, 每一个点代表一个字符。 那么abc是不是三个字符呀?是, 所以满足条件。

    • replaceAll : String一个非常好用的方法
    package com.string;
    
    public class RegexTest {
    
        public static void main(String[] args) {
            /*
             * 最简单的正则表达式
             * 这里使用的是String类的matches方法.
             * 这个方法是比较字符是否匹配
             * .表示的时任意一个字符
             */
            System.out.println("abc".matches("..."));
            /**
             * String的另一个很有用的方法: replaceAll,这个方法有两个参数
             * 第一个参数: regex正则表达式
             * 第二个参数: 替换的字符串
             * 下面这个语句的含义: 替换所有的数组为-
             */
            System.out.println("a43215b".replaceAll("\d", "-"));
        }
    }
    运行结果
    true
    a-----b

    String的另一个很有用的方法: replaceAll,这个方法有两个参数。
    replaceAll(String regex, String replacement) : 字符串匹配正则表达式, 匹配成功的替换为第二个参数自定的字符串
    •  简单认识pattern和Marcher
      package com.string;
      
      import java.util.regex.Matcher;
      import java.util.regex.Pattern;
      
      public class RegexTest {
      
          public static void main(String[] args) {
              
              /**
               * 简单认识Pattern 和 Matcher
               */
              //compile:方法, 指的是将一个正则表达式先编译, 这样做的好处是效率提高了.
              //[a-z]:表示的事,a-z任意一个字符
              //{3} 表示的是3个
              Pattern p = Pattern.compile("[a-z]{3}");
              //matcher方法是创建一个输入与匹配模式的匹配器.
              Matcher m = p.matcher("abx");
              //尝试将整个区域与模式进行匹配
              System.out.println(m.matches());
              /*
               * 上面3句话可以使用下面一句话代替. 但为什么还要用三句话来写呢?
               * 1. 通过Parrern.compile编译以后, 速度回大幅度提高
               * 2. 可以很使用Pattern和Matcher的一些方法
               */
              System.out.println("abc".matches("[a-z]{3}"));        
          }
      }

      上面3句话可以使用下面一句话代替. 但为什么还要用三句话来写呢?
      * 1. 通过Parrern.compile编译以后, 速度回大幅度提高
      * 2. 可以很使用Pattern和Matcher的一些方法

    二、认识正则表达式

    1. 初识 . * + ? {n} {n,} {n,m}
      • . 代表任意字符
      • * 代表0或者多个
      • + 代表1个或者多个
      • ? 代表0或者1个
      • {n} :代表某一个字符出现指定的次数
      • {n,}: 至少出现某个字符n次
      • {n, m}: 至少n次, 至多m次
        package com.string;
        
        import java.util.regex.Matcher;
        import java.util.regex.Pattern;
        
        public class RegexTest2 {
        
            public static void main(String[] args) {
                /**
                 * 初识 . * + ?
                 * . 代表任意字符
                 * * 代表0或者多个
                 * + 代表1个或者多个
                 * ? 代表0或者1个
                 * {n} :代表某一个字符出现指定的次数
                 * {n,}: 至少出现某个字符n次
                 * {n, m}: 至少n次, 至多m次
                 */
                System.out.println("aaa".matches("..."));
                System.out.println("a".matches("."));
                System.out.println("aa".matches("aa"));
                System.out.println("aaa".matches("a*"));
                System.out.println("aaa".matches("a+"));
                System.out.println("".matches("a*"));
                System.out.println("aaa".matches("a?"));
                System.out.println("".matches("a?"));
                System.out.println("a".matches("a?"));
                System.out.println("23568745896512".matches("\d{3,100}"));
                /*
                 * \d表示任意有效字符.
                 * . 表示的是常用的.,但是.在正则表达式中有特殊含义(任意字符), 所以需要转义为. 
                 * 而在正则表达式中也是特殊字符, 所以还需要再加一个. 因此就是\.
                 * 
                 *  下面这个例子是一个简单的ip地址的匹配. 但是如果超出了256怎么办呢?可以再用更详细的方法限定
                 */
                System.out.println("192.168.203.aaa".matches("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"));
                //这是一种简单的方法
                System.out.println("192".matches("[0-2][0-9][0-9]"));
                
                
            }
        }

        运行结果

        true
        true
        true
        true
        true
        true
        false
        true
        true
        true
        false
        true
    2. 范围 []
      /**
               * 范围
               * 1. 中括号表示范围
               * 2. 每个范围只对应一个字符, 无论这个范围有多长
               * 3.  
               */
              System.out.println("=========================================");
              //中括号表示范围,abc表示确定范围 
              System.out.println("a".matches("[abc]"));
              //a-z表示一个指定的范围
              System.out.println("a".matches("[a-z]"));
              //表示的时或, a-z或者A-Z,满足一个条件即可
              System.out.println("a".matches("[a-zA-Z]"));
              //或者的另一种表示方法,使用分隔符|
              System.out.println("a".matches("[a-z]|[A-Z]"));
              //或的另一种表示方法
              System.out.println("a".matches("[a-z[A-Z]]"));
              //交集的表示方法
              System.out.println("R".matches("[A-Z&&[Q-Z]]"));

      中括号表示范围, 这个范围限定的时一个字符. 上面的案例显示了并集的表示方法, 交集的表示方法.

    3. 认识 s w d
      • s 表示的时空白字符,包括[ f x0B]
      • S表示的时非空白字符,即[^s]
      • w: 表示的是字母字符, 包括[a-zA-Z_0-9]
      • W: 表示的是非字母字符, 即[^w]
      • d: 表示的是数字,范围[0-9]
      • D: 表示的时非数字, 即[^0-9] 或者 [^d]
      • 在正则表达式中使用四个表示. 即\\. 下面的例子说了为什么这样表示. java中的使用的是两个\, 即\
               /**
                 * 认识 s w d 
                 * s: 代表空白字符 :[ 	
        x0Bf
        ]
                 * S: 代表非空白字符, 除了空白字符以外的字符  [^s]
                 * w: 单词字符 [a-zA-Z_0-9]
                 * W: 非单词字符 [^w]
                 * 
                 * d: 表示的时数字[0-9]
                 * D: 表示的时非数字[^d]或者[^0-9]
                 */
                System.out.println("============================");
                /*
                 * s表示的时空白字符[ 
        	x08f
        ]. 在正则表达式中, s本身代表的是空白字符. 由于有特殊的含义,
                 * 所以, 在写s的时候, 需要写成\s.
                 * 下面这句话是匹配4个空白字符 - true
                 */
                System.out.println(" 
        	
        ".matches("\s{4}"));
                //S表示的时非空白字符, 空格是空白字符, 所以返回false
                System.out.println(" ".matches("\S"));
                //\w匹配的是单词字符, 单词字符的范围是[a-zA-Z_0-9], 所以返回的时-true
                System.out.println("a_8".matches("\w{1,3}"));
                /*
                 * 下面这句话的含义
                 * [a-z]{0,3}表示0-3个字符
                 * \d+:表示的是1个或多个数字
                 * [&^%$]+: 表示的时中括号中的一个或者多个
                 */
                System.out.println("abc888&^%".matches("[a-z]{0,3}\d+[&^%#]+"));
                /*
                 * 下面说说本身
                 * 正则表达式如何表示斜杠呢. 比如我有一个反斜杠, 如何匹配?
                 * 
                 * 首先在java中, 是有特殊含义的. 比如"表示的是一个". 如果想表示字符串类型的\, 不能直接使用"",因为后一个双引号会被转义.
                 * 因此在java中,想要表示\,需要使用\
                 * 
                 * 在正则表达式中, 有特殊的含义, 比如s d w. 因此表示需要使用\. 然后\表示的是一个\, 和后面的"会发生转义. 
                 * 我们采取的方式是对这两个反斜杠都进行转义, 所以就是\\.
                 * 
                 */
                System.out.println("\".matches("\\"));
                
    4. 正则表达式的边界处理
      • ^ : 行的开头
      • $行的几位
      • 单词边界
      • B非单词边界
        /**
                 * 边界字符
                 * ^: 行的开头
                 * $: 行的结尾
                 * : 单词边界
                 * B: 非单词边界
                 */
                System.out.println("===============================");
                /*
                 * ^表示的是行的开头. 写在一行的最前面
                 * 表示以a开头,后面跟着1个或者多个字符
                 */
                System.out.println("abc".matches("^a.*"));
                /*
                 * $表示行的结尾. 如果$出现在最后, 则表示这一行已经结尾了.
                 * 下面的正则表达式表示, 以任意字符结尾
                 */
                System.out.println("def".matches(".*$"));
                //以h开头
                System.out.println("hello sir".matches("^h.*"));
                //以ir结尾
                System.out.println("hello sir".matches(".*ir$"));
                /*
                 * 下面这个语句的含义
                 * ^h: 以h开头
                 * \w{0,3}: h后面跟着0-3个单词字符
                 * o: 后面跟着一个o
                 * : 表示的是单词的结尾. 
                 * .*: 表示1个或多个字符
                 * ir$: 以ir结尾
                 */
                System.out.println("hello sir".matches("^h\w{0,3}o\b.*ir$"));
                /*
                 * 下面这个案例返回false, 和上面的区别是, 单词hello, o不是单词的结尾
                 */
                System.out.println("hellosir".matches("^h\w{0,3}o\b.*ir$"));
                
                /*
                 * 如何匹配带有空格的空白行. 空白行虽然没有字符, 但是这一行可能有空白字符, 如空格等.
                 * java中,换行用
        表示
                 * 
                 */
                System.out.println(" 
        ".matches("^[\s&&[^\n]]*\n$"));
                
        ===============================
        true
        true
        true
        true
        true
        false
        true

         练习: 单词边界

        /**
                 * 小练习
                 */
                System.out.println("aaa 8888c".matches(".*\d{4}."));
                System.out.println("aaa 8888c".matches(".*\b\d{4}."));
                System.out.println("aaa8888c".matches(".*\d{4}."));
                System.out.println("aaa8888c".matches(".*\b\d{4}."));
        true
        true
        true
        false

        匹配邮箱

        //匹配邮箱
        System.out.println("asdfgh.wett@weryvd.com".matches("[\w[\.\-]]+@\w+\.\w+"));

    三、Pattern和Matcher

    1. mathes的用法:匹配整个字符串, 也就是判断是否整个字符串是否完全匹配正则表达式. 
      public static void main(String[] args) {
              /**
               * 使用Matcher和Pattern匹配字符串
               */
              Pattern p = Pattern.compile("\d{3,5}");
              String str = "123-45678-456-78";
              //将str和正则表达式p进行匹配
              Matcher m = p.matcher(str);
              
              //matches:匹配整个字符串--首先位数就不匹配, 所以返回false
              System.out.println(m.matches());
          }

      结果:

      false

      分析:正则表达式是3-5个数组, 而str字符串第四个字符就不是数字, 所以返回false

    2. find()的用法:查找正则表达式,只要有符合条件的, 就返回true
      public static void main(String[] args) {
              /**
               * 使用Matcher和Pattern匹配字符串
               */
              Pattern p = Pattern.compile("\d{3,5}");
              String str = "123-45678-456-78";
              //将str和正则表达式p进行匹配
              Matcher m = p.matcher(str);
              //find: 从整个字符串中查找, 返回的是,剩下的字符串
              System.out.println(m.find());
              System.out.println(m.find());
              System.out.println(m.find());
              System.out.println(m.find());
          }

      结果:

      true
      true
      true
      false

      分析: find是查找符合条件的字符串, 找到以后就把这个字符串吃了. 当在使用find查找的时候, 会在剩下的字符串中进行匹配, 所以, 前三个返回的是true,第四个返回的是false.

      fa

    3. matches和find会相互影响
      package com.string;
      
      import java.util.regex.Matcher;
      import java.util.regex.Pattern;
      
      public class RegexTest3 {
      
          public static void main(String[] args) {
              /**
               * 使用Matcher和Pattern匹配字符串
               */
              Pattern p = Pattern.compile("\d{3,5}");
              String str = "123-45678-456-78";
              //将str和正则表达式p进行匹配
              Matcher m = p.matcher(str);
              
              //matches:匹配整个字符串--首先位数就不匹配, 所以返回false
              System.out.println(m.matches());
              //find: 从整个字符串中查找, 返回的是,剩下的字符串
              System.out.println(m.find());
              System.out.println(m.find());
              System.out.println(m.find());
              System.out.println(m.find());
          }
      }

      运行结果:

      false
      true
      true
      false
      false

      分析: 这次为什么后两个find都是返回的false呢?因为第一个matches匹配到第四个字符的时候,正则表达式判断, 匹配失败. 那么下面再find查找的时候, 是从第五个字符开始的

    4. lookingAt:每次都是从头开始查找, 看是否有符合条件的. 
      public static void main(String[] args) {
              /**
               * 使用Matcher和Pattern匹配字符串
               */
              Pattern p = Pattern.compile("\d{3,5}");
              String str = "123-45678-456-78";
              //将str和正则表达式p进行匹配
              Matcher m = p.matcher(str);
              
              
              //lookingAt():从头开始查找
              System.out.println(m.lookingAt());
              System.out.println(m.lookingAt());
              System.out.println(m.lookingAt());
              System.out.println(m.lookingAt());
          }

      运行结果:

      true
      true
      true
      true

      分析: 每次都从头开始找, 所以,每次都能匹配成功

    5. reset():重置。将光标移动到字符串的最开始。 我们在第3个例子中看到了。 matches方法的执行,影响到了find的运行。 加入我的find就要从字符串开始查找,怎么办呢, 使用reset()
      public static void main(String[] args) {
              /**
               * 使用Matcher和Pattern匹配字符串
               */
              Pattern p = Pattern.compile("\d{3,5}");
              String str = "123-45678-456-78";
              //将str和正则表达式p进行匹配
              Matcher m = p.matcher(str);
              
              //matches:匹配整个字符串--首先位数就不匹配, 所以返回false
              System.out.println(m.matches());
              m.reset();
              //find: 从整个字符串中查找, 返回的是,剩下的字符串
              System.out.println(m.find());
              System.out.println(m.find());
              System.out.println(m.find());
              System.out.println(m.find());
      }

      运行结果:

      false
      true
      true
      true
      false

      分析: 这样就可以看出, matches方法的运行,并没有影响到find。find查找到第四次的时候,查找失败了。

    6. start()和end()方法: 
      • 上面使用find()方法找到了字符串, 那么怎么知道找到的字符串的位置呢? 使用start()和end()就可查看位置了
      • start()和end()方法必须使用在能够find到字符的位置, 如果find返回false, 使用start和end会异常
      • start()和end():都是从0 开始计数. 返回的区间包括start,不包括end
        public static void main(String[] args) {
                /**
                 * 使用Matcher和Pattern匹配字符串
                 */
                Pattern p = Pattern.compile("\d{3,5}");
                String str = "123-45678-456-78";
                //将str和正则表达式p进行匹配
                Matcher m = p.matcher(str);
                
                //matches:匹配整个字符串--首先位数就不匹配, 所以返回false
                System.out.println(m.matches());
                m.reset();
                //find: 从整个字符串中查找, 返回的是,剩下的字符串
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
                System.out.println(m.find());
            }

        运行结果:

        false
        true
        0-3
        true
        4-9
        true
        10-13
        false

        返回的0-3. 包括0,不包括3. 也就是start从0开始, end到字符结束的下一位

        下面看看,如果find返回的是false , 会如何呢?

        public static void main(String[] args) {
                /**
                 * 使用Matcher和Pattern匹配字符串
                 */
                Pattern p = Pattern.compile("\d{3,5}");
                String str = "123-45678-456-78";
                //将str和正则表达式p进行匹配
                Matcher m = p.matcher(str);
                
                //matches:匹配整个字符串--首先位数就不匹配, 所以返回false
                System.out.println(m.matches());
                m.reset();
                //find: 从整个字符串中查找, 返回的是,剩下的字符串
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
                System.out.println(m.find());
                System.out.println(m.start() + "-" + m.end());
        }

        运行结果:

        false
        true
        0-3
        true
        4-9
        true
        10-13
        false
        Exception in thread "main" java.lang.IllegalStateException: No match available
            at java.util.regex.Matcher.start(Matcher.java:342)
            at com.string.RegexTest3.main(RegexTest3.java:28)
    7. replaceAll方法和appendReplacement()方法的使用
      • 案例一: 找到符合正则表达式的字符串,并打印输出.

        /**
                 * replaceAll
                 */
                Pattern pp = Pattern.compile("java");
                String ss = "java Java JaVa JAva IloveJava you hateJaVA ";
                Matcher mm = pp.matcher(ss);
                /*
                 * 需求一: 找到所有符合条件字符串
                 * 很显然, 只有一个符合条件, 找到并打印出来
                 */
                if(mm.find()){
                    //mm.group()打印输出这个组的内容
                    System.out.println(mm.group());
                }

        很显然这里只能找到一个符合添加的. 那就是java. 其他大小写不符合.

      • 案例二: 不区分大小写, 替换所有的java为大写。 这里使用到了Pattern的另一个构造方法compile(regex, flag). flag有一些固定的值. 可以参考api

             CASE_INSENSITIVE:大小写不敏感, 即不区分大小写. 我们这里使用的就是这个

    /*
             * 需求二: 不区分大小写,查找所有符合条件的字符串, 将其替换为大写
             */
            //第二个参数代表,大小写不敏感
            Pattern pp2 = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
            String ss2 = "java Java JaVa JAva IloveJava you hateJaVA ";
            Matcher mm2 = pp2.matcher(ss);
    
            //查找替换直接使用replaceAll即可
            //下面这句话的含义: 查找所有符合条件的表达式,并将其替换为JAVA
            System.out.println(mm2.replaceAll("JAVA"));

          replaceAll: 查找并替换.

      • 案例三: 不区分大小写, 查找所有的字符串, 将奇数个替换为java, 偶数个替换为JAVA
        //第二个参数代表,大小写不敏感
        Pattern pp2 = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
        String ss2 = "java Java JaVa JAva IloveJava you hateJaVA faddafdfa";
        Matcher mm2 = pp2.matcher(ss);
        
        /*
         * 需求三: 不区分大小写, 查找所有符合条件的字符串. 将其奇数个替换为java, 偶数个替换为JAVA
         * 
         * 方法有很多, 我们介绍一个Matcher的新方法appendReplacement()
         */
        int num = 0;
        StringBuffer buf = new StringBuffer();
        while(mm2.find()){
            num ++;
            if(num % 2 == 0){
                mm2.appendReplacement(buf, "JAVA");
            } else {
                mm2.appendReplacement(buf, "java");
            }
        }
        //最后打印buffer, 因为最后的结果都填到buffer里面了
        System.out.println(buf);

        运行结果:

        java JAVA java JAVA Ilovejava you hateJAVA

        appendReplacement()方法:   这里使用了appendReplacement()方法. 这个方法的含义是: 查找符合条件的字符串, 将其替换为第二个参数. 然后将整个字符串拼接到第一个参数中.

        .下面我们再来看看这个方法到底是如何工作的

        //第二个参数代表,大小写不敏感
        Pattern pp2 = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
        String ss2 = "java Java JaVa JAva IloveJava you hateJaVA fabdafdfa";
        Matcher mm2 = pp2.matcher(ss);
        /*
         * 需求三: 不区分大小写, 查找所有符合条件的字符串. 将其奇数个替换为java, 偶数个替换为JAVA
         * 
         * 方法有很多, 我们介绍一个Matcher的新方法appendReplacement()
         *  
         */
        int num = 0;
        StringBuffer buf = new StringBuffer();
        while(mm2.find()){
            num ++;
            if(num % 2 == 0){
                mm2.appendReplacement(buf, "JAVA");
                System.out.println(buf);
            } else {
                mm2.appendReplacement(buf, "java");
                System.out.println(buf);
            }
        }
        //最后打印buffer, 因为最后的结果都填到buffer里面了
        System.out.println(buf);

        运行结果:

        java
        java JAVA
        java JAVA java
        java JAVA java JAVA
        java JAVA java JAVA Ilovejava
        java JAVA java JAVA Ilovejava you hateJAVA
        java JAVA java JAVA Ilovejava you hateJAVA

        分析: 在这里我们打印出了每一个输出. 发现. 首先先进行find, 一旦find成功, 这就是一组. 然后将这一组中符合条件的字符串替换为指定的字符. 例如: 第一组, 查找java, 找到了以后, 将其全部替换为小写的java. 然后将其append到buf中。 第二次查找, 从下一个字符开始找. 找到了一个空格和Java. 然后将符合条件的Java替换为JAVA, 然后将空格和JAVA填充到buf中. 第三次第四次也是如此, 看第五次, 匹配到的是空格IloveJava, 符合条件的时Java, 将其替换为小写的java. 最后将Ilovejava给append到buf中. 

        所以, 最后的输出结果是java JAVA java JAVA Ilovejava you hateJAVA

        认证观察我们会发现, 最后有一个字符串 fabdafdfa不见了. 这是怎么回事呢. 我们最后没有添加尾巴. 要求我们在find完成以后, 将最后的尾巴添加进来, 使用mm2.appendTail();

        //第二个参数代表,大小写不敏感
        Pattern pp2 = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
        String ss2 = "java Java JaVa JAva IloveJava you hateJaVA faddafdfa";
        Matcher mm2 = pp2.matcher(ss);
        
        //查找替换直接使用replaceAll即可
        //下面这句话的含义: 查找所有符合条件的表达式,并将其替换为JAVA
        System.out.println(mm2.replaceAll("JAVA"));
        mm2.reset();
        /*
         * 需求三: 不区分大小写, 查找所有符合条件的字符串. 将其奇数个替换为java, 偶数个替换为JAVA
         * 
         * 方法有很多, 我们介绍一个Matcher的新方法appendReplacement()
         *  
         */
        int num = 0;
        StringBuffer buf = new StringBuffer();
        while(mm2.find()){
            num ++;
            if(num % 2 == 0){
                mm2.appendReplacement(buf, "JAVA");
                System.out.println(buf);
            } else {
                mm2.appendReplacement(buf, "java");
                System.out.println(buf);
            }
        }
        mm2.appendTail(buf);
        //最后打印buffer, 因为最后的结果都填到buffer里面了
        System.out.println(buf);

        运行结果: 

        java JAVA java JAVA Ilovejava you hateJAVA faddafdfa

        整个字符串就都包含在内了.


      • /**
             * 分组
             */
            /*
             * 案例一: 我们来看一个分组的简单例子
             */
            //这个正则表达式的含义是. 数字3-5个后跟两个字母
            Pattern pp3 = Pattern.compile("\d{3,5}[a-z]{2}");
            String str3 = "45896aa-758dd-632ee-00a";
            Matcher mm3 = pp3.matcher(str3);
            
            /*
             * 分析: 这里面有几个符合条件呢?
             * 目测3个
             */
            while(mm3.find()){
                System.out.println(mm3.group());
            }

      8. 分组group()分组. 下面来看案例

      • 案例一: 一个简单的小例子: 使用分组打印匹配成功的字符串
            /**
             * 分组
             */
            /*
             * 案例一: 我们来看一个分组的简单例子
             */
            //这个正则表达式的含义是. 数字3-5个后跟两个字母
            Pattern pp3 = Pattern.compile("\d{3,5}[a-z]{2}");
            String str3 = "45896aa-758dd-632ee-00a";
            Matcher mm3 = pp3.matcher(str3);
            
            /*
             * 分析: 这里面有几个符合条件呢?
             * 目测3个
             */
            while(mm3.find()){
                System.out.println(mm3.group());
            }

        输出结果:

        45896aa
        758dd
        632ee

        我们看到, 如预期的, 有三组满足条件.

        那么, 如果我想要得到三组中每一组的数字,怎么办呢?看案例二

      • 案例二: 得到分组后,每一组的字符串. 这里有几个知识点
        • 使用()对正则表达式进行分组
        • 到底是第几组?从左括号开始计算, 第几个括号就是第几组
        • 分好的组可以通过group(组号) 获得相应的内容
        • 获取不存在的组将报异常
        • fda
        • fa
              /*
               * 案例二: 获得上一个案例中每一组的数字.
               * 
               * 这里才真正涉及到了分组的概念
               * 我们可以在正则表达式通过()来进行分组, 例如\d{3,5}[a-z]{2}表示的时3-5个数字, 2个字符. 我们将数字分为一组, 字母分为一组. 
               * 正则表达式的写法如下(\d{3,5})([a-z]{2}). 这样呢就分好组了, 其实, 在这里一共是有三组, 整个字符串也算作一组.
               * 
               * 分号组以后, 我们通过组号来获取每一组的内容. 如何知道我要获取的时哪一组呢? 看左括号, 第几个左括号,就是第几组.
               * 获取不存在的组将报异常
               */
              Pattern pp4 = Pattern.compile("(\d{3,5})([a-z]{2})");
              String str4 = "45896aa-758dd-632ee-00a";
              Matcher mm4 = pp4.matcher(str4);
              System.out.println("获取整个组的内容");
              while(mm4.find()){
                  System.out.println(mm4.group());
              }
              System.out.println("获取第一组---全部是数字的组");
              mm4.reset();
              while(mm4.find()){
                  System.out.println(mm4.group(1));
              }
              System.out.println("获取第二组---全部是字母的组");
              mm4.reset();
              while(mm4.find()){
                  System.out.println(mm4.group(2));
              }

          运行结果:

          获取整个组的内容
          45896aa
          758dd
          632ee
          获取第一组---全部是数字的组
          45896
          758
          632
          获取第二组---全部是字母的组
          aa
          dd
          ee

       9. Qualifier: 限定符,修饰符

        在API文档中的限定修饰符有3类: 如下图

        

        仔细看这三类的描述会发现. 他们的注释都一模一样. 

        第一类Greedy Quantifiers --> 贪婪的修饰符

        第二类 Reluctant quantifiers --> 不情愿的修饰符

        第三类 Possessive quantifiers --> 独占的修饰符

        而这三类中每一类对应的文字描述又都是一样的,那么, 他们到底有什么区别呢?  看下面的例子: 

    • 第一类Greedy Quantifiers --> 贪婪的修饰符
          String str = "aaaa9bbbb8";
          //贪婪的修饰符--Greedy Quanlifiers
          Pattern p1 = Pattern.compile("(.{3,10})[0-9]");
          Matcher m1 = p1.matcher(str);
          
          if(m1.find()){
              System.out.println(m1.start() + "-" + m1.end());
          }
          /**
           * 运行结果: 0-10
           * 
           * 结果分析: 
           * Greedy Quanlifiers --贪婪的修饰符  工作原理
           * 为什么叫她贪婪的呢? 因为, 他在匹配的时候首先匹配3-10个任意字符. 
           * 他会去自动匹配最多字符,10个. 这就是为什么说他是贪婪的原因
           * 当匹配了10个字符以后, 发现不满足条件, 于是他减少一个, 看看是否满足条件, 如果满足,就直接反悔了
           */

      运行结果: 

      0-10

      结果分析: 

      运行结果: 0-10
       
      Greedy Quanlifiers --贪婪的修饰符  工作原理
      为什么叫她贪婪的呢? 因为, 他在匹配的时候首先匹配3-10个任意字符. 
      他会去自动匹配最多字符,10个. 这就是为什么说他是贪婪的原因
      当匹配了10个字符以后, 发现不满足条件, 于是他减少一个, 看看是否满足条件, 如果满足,就直接反悔了
    •  第二类 Reluctant quantifiers --> 不情愿的修饰符
      //不情愿的修饰符--Reluctant Quanlifiers
          String str = "aaaa9bbbb8";
          Pattern p2 = Pattern.compile("(.{3,10}?)[0-9]");
          Matcher m2 = p2.matcher(str);
          
          if(m2.find()){
              System.out.println(m2.start() + "-" + m2.end());
          }
          
          /**
           * 运行结果: 0-5
           * 
           * 结果分析: 
           * 不情愿的修饰符--Reluctant Quanlifiers  工作原理
           * 仅仅是多了一个问号, 为什么结果却变成了0-5个呢
           * 因为不情愿. 怎么个不情愿呢? 不是要匹配3-10个字符么, 那我就先匹配3个. 不情愿嘛. 
           * 匹配完3个,看看后面的字符是否符合条件.不符合, 那就在匹配四个, 四个符合了. 后面整个是一个数字.
           * 所以匹配的结果就是0-5了
           */

      运行结果:

      0-5

      结果分析:
      * Greedy Quanlifiers --贪婪的修饰符 工作原理
      * 为什么叫她贪婪的呢? 因为, 他在匹配的时候首先匹配3-10个任意字符.
      * 他会去自动匹配最多字符,10个. 这就是为什么说他是贪婪的原因
      * 当匹配了10个字符以后, 发现不满足条件, 于是他减少一个, 看看是否满足条件, 如果满足,就直接反悔了

    • 第三类 Possessive quantifiers --> 独占的修饰符
          String str = "aaaa9bbbb8";
          //不情愿的修饰符--Reluctant Quanlifiers
          Pattern p3 = Pattern.compile("(.{3,10}+)[0-9]");
          Matcher m3 = p3.matcher(str);
          
          if(m3.find()){
              System.out.println(m3.start() + "-" + m3.end());
          }else{
              System.out.println("not match !");
          }
          /**
           * 运行结果: not match!
           * 
           * 不情愿的修饰符--Reluctant Quanlifiers 工作原理
           * 真奇怪, 怎么返回的是不匹配呢?
           * Reluctant Quanlifiers是这么工作的. 你不是要匹配3-10个字符么. 我就匹配10个, 然后看是否符合条件. 
           * 如何条件则返回, 不符合条件的话我不会减少字符, 直接返回不匹配.
           * 
           * 也就是按照最大字符进行匹配, 符合条件,匹配成功, 不符合条件, 对不起, 匹配失败.
           * 
           */

      运行结果:

      not match !

      结果分析

      * 不情愿的修饰符--Reluctant Quanlifiers 工作原理
      * 真奇怪, 怎么返回的是不匹配呢?
      * Reluctant Quanlifiers是这么工作的. 你不是要匹配3-10个字符么. 我就匹配10个, 然后看是否符合条件.
      * 如何条件则返回, 不符合条件的话我不会减少字符, 直接返回不匹配.
      *
      * 也就是按照最大字符进行匹配, 符合条件,匹配成功, 不符合条件, 对不起, 匹配失败.

      9. 非捕获组-non capturing

        什么是非捕获组呢? 看看下面的案例

      • (?=x)  API的解释 X, via zero-width positive lookahead. 这个解释不是很清楚, 我们来看案例

        a) 下面这个案例是没有使用非捕获组. 匹配3个任意字符

        Pattern p1 = Pattern.compile(".{3}");
        String str1 = "ab2dd4";
        Matcher m1 = p1.matcher(str1);
        while(m1.find()){
            System.out.println(m1.group());
        }

        输出结果

        ab2
        dd4

        这个案例很简单. 为使用捕获组做个铺垫

        2) 在上一个案例的基础上。有了新的要求, 要求第三个字符必须是数字2. 我们用常规思想如何实现呢?修改正则表达式“.{2}2”
        Pattern p11 = Pattern.compile(".{2}2");
        String str11 = "ab2dd4";
        Matcher m11 = p11.matcher(str11);
        while(m11.find()){
            System.out.println(m11.group());
        }

        输出结果

        ab2

        结果符合条件, 只打印出了一组

        3) 同样的需求, 我们使用非捕获组来实现: 正则表达式改为".{3}(?=2)"

        /**
         * non capturing--非捕获组
         * 什么是非捕获组呢? 我们来看看下面的案例
         */
        
        /* 那么现在我提升需求: 要求打印出来的字符必须以数字2结尾.
         * 能够想到的做法是什么?
         * 正则表达式改为".{2}2", 这个肯定没问题
         * 我们还有一种方法,使用非捕获组  (?=X)
         * 
         * 我们知道?匹配的是0个或者1个字符. 当?在一个组中作为开头的时候, 表示的是非捕获组
         * 
         * 来看看下面你的demo
         */
        Pattern p2 = Pattern.compile(".{3}(?=2)");
        String str2 = "ab2dd4";
        Matcher m2 = p2.matcher(str2);
        while(m2.find()){
            System.out.println(m2.group());
        }

        其中(?=x) 就是非捕获组表达式的一种形式 .

        运行结果:

        * 什么都没有输出, 为什么?
        * 来分析正则表达式. 前面有三个任意字符, 后面紧跟着一个2. 并且2不被捕获
        * 而我们的字符串:有没有三个任意字符后面紧跟着一个2呢? 没有. 只有两个任意字符后跟着一个2. 所以匹配不到
        * 改成下面这样是不是就可以成功了?

        Pattern p3 = Pattern.compile(".{3}(?=2)");
        String str3 = "abc2dd4";
        Matcher m3 = p3.matcher(str3);
        while(m3.find()){
            System.out.println(m3.group());
        }

        运行结果:

        abc

        * 输出结果: abc
        * 果然成功了.
        *
        * 在来看看如果将(?=2)放在前面, 会得到什么结果呢?
        * 预期: "(?=2).{3}", 根据上面的预期, 得到的记过应该是dd4
        * 来看看实际结果

        Pattern p4 = Pattern.compile("(?=2).{3}");
        String str4 = "abc2dd4";
        Matcher m4 = p4.matcher(str4);
        while(m4.find()){
            System.out.println(m4.group());
        }

        运行结果

        2dd

        * 输出结果: 2dd.
        * 和预期不一样哦.
        * 我们再来分析一下这个正则表达式. (?=2).{3} 以2开头的3个字符. API上还有一个关键字,lookahead. 表示朝前看.
        * 也就是说:如果在前面, 则包含这个字符, 如果在后面, 则不包含这个字符.

        总结: 当(?=x) 放在表达式的结尾时, 不包含这个字符. 当(?=x)放在表达式开头时, 就会包含指定的字符.

      • (?!X)  表示不是某个字符. 放在表达式的前面表示: 表达式不是以这个字符开头, 放在表达式的后面表示, 表达式后面跟着的不是这个字符. 看例子:
        /**
         * (?!2).{3}含义: 不是以2开头的3个字符.
         */
        
        Pattern p5 = Pattern.compile("(?!2).{3}");
        String str5 = "abc2dd4";
        Matcher m5 = p5.matcher(str5);
        while(m5.find()){
            System.out.println(m5.group());
        }

        运行结果:

        abc
        dd4

         分析: 

        * 首先取3个字符abc, 是以2开头么? 不是, 所以字符串符合.
        * 看接下来的字符串2dd4. 取3个2dd, 是不是以2开头, 是. 所以, 放弃.
        * 向后以一位, 看dd4. 这三个字符是以2开头么? 不是, 符合条件
        * 所以结果: abc dd4

        那么把(?!2) 放在后面呢? 表示的是, 后面跟着的字符不是2
        /**
         * .{3}(?!2)含义: 3个任意字符,后面跟着的不是2.
         */
        
        Pattern p6 = Pattern.compile(".{3}(?!2)");
        String str6 = "abc2dd4";
        Matcher m6 = p6.matcher(str6);
        while(m6.find()){
            System.out.println(m6.group());
        }

        运行结果:

        bc2
        dd4

        * 分析: 首先取3个字符abc, 后面跟着的是2么? 是, 不符合条件. 所以向后移一位
        * bc2, 后面这着的是2么? 不是, 符合条件
        * 然后看剩下的字符dd4. 后面跟着的也不是2, 符合条件

      • (?<=X) 这个表达式的含义正好和(?=X相反), 看下面的例子就知道怎么回事了
        /**
         * (?<=2)含义: 与(?=2)的含义正好相反. 
         * 
         * (?=2).{3} :任意3个字符, 以2开头
         * (?<=2).{3}:任意3个字符, 前面一个字符是2
         * 
         * .{3}(?=2): 任意三个字符, 后面紧跟着的一个字符是2
         * .{3}(?<=2): 任意三个字符, 三个字符中最后一个字符是2
         * 
         * 看下面的例子
         * 
         */
        System.out.println("=====(?=2)在前======");
        Pattern p7 = Pattern.compile("(?=2).{3}");
        String str7 = "abc2dd4";
        Matcher m7 = p7.matcher(str7);
        while(m7.find()){
            System.out.println(m7.group());
        }
        
        System.out.println("=====(?<=2)在前======");
        Pattern p8 = Pattern.compile("(?<=2).{3}");
        String str8 = "abc2dd4";
        Matcher m8 = p8.matcher(str8);
        while(m8.find()){
            System.out.println(m8.group());
        }
        
        
        System.out.println("=====(?=2)在后======");
        Pattern p9 = Pattern.compile(".{3}(?=2)");
        String str9 = "abc2dd4";
        Matcher m9 = p9.matcher(str9);
        while(m9.find()){
            System.out.println(m9.group());
        }
        
        
        System.out.println("=====(?<=2)在后======");
        Pattern p10 = Pattern.compile(".{3}(?<=2)");
        String str10 = "abc2dd4";
        Matcher m10 = p10.matcher(str10);
        while(m10.find()){
            System.out.println(m10.group());
        }

        运行结果:

        =====(?=2)在前======
        2dd
        =====(?<=2)在前======
        dd4
        =====(?=2)在后======
        abc
        =====(?<=2)在后======
        bc2

        分析看注释就好了, 很详细

      • (?<!X) : 这个表达式的含义和(?!X) 正好相反, 看下面的案例
        /**
         * 
         * (?<!2)的含义: 与(?!2)的含义正好想法
         * !2表示的是不是2
         * 
         * (?!2).{3} :任意三个字符,这三个字符中第一个字符不是2
         * .{3}(?!2): 任意三个字符, 这三个字符后面跟着的不是2
         * 
         * (?<!2).{3}:任意三个字符, 这三个字符的前一个字符不是2
         * 
         * .{3}(?<!2): 任意三个字符, 这三个字符中最后一个不是2
         * 
         * 看下面的例子
         * 
         */
        System.out.println("=====(?!2)在前======");
        Pattern p77 = Pattern.compile("(?!2).{3}");
        String str77 = "abc2dd4";
        Matcher m77 = p77.matcher(str77);
        while(m77.find()){
            System.out.println(m77.group());
        }
        
        System.out.println("=====(?<!2)在前======");
        Pattern p88 = Pattern.compile("(?<!2).{3}");
        String str88 = "abc2dd4";
        Matcher m88 = p88.matcher(str88);
        while(m88.find()){
            System.out.println(m88.group());
        }
        
        
        System.out.println("=====(?!2)在后======");
        Pattern p99 = Pattern.compile(".{3}(?!2)");
        String str99 = "abc2dd4";
        Matcher m99 = p99.matcher(str99);
        while(m99.find()){
            System.out.println(m99.group());
        }
        
        
        System.out.println("=====(?<!2)在后======");
        Pattern p100 = Pattern.compile(".{3}(?<!2)");
        String str100 = "abc2dd4";
        Matcher m100 = p100.matcher(str100);
        while(m100.find()){
            System.out.println(m100.group());
        }

        运行结果:

        =====(?!2)在前======
        abc
        dd4
        =====(?<!2)在前======
        abc
        2dd
        =====(?!2)在后======
        bc2
        dd4
        =====(?<!2)在后======
        abc
        2dd
      • 10. 向前引用 --back refenerence, 看例子, 了解其含义
        /**
         * back Refenences:向前引用
        * \1 表示的是第一组, 表示和第一组的内容保持一致
        */ System.out.println("=====back Refenences:======"); Pattern p110 = Pattern.compile("(\d\d)\1"); String str110 = "1212"; Matcher m110 = p110.matcher(str110); System.out.println(m110.matches()); /** * "(\d\d)\1" : (\d\d)表示的是一个组, 这个组里有两个数字. \1,表示的是, 后面跟着的数组和第一组一致 * 来看字符串1212: 两个数字匹配到12. 后面的字符串要和第一个组一致. 所以也是12. 匹配成功 */

        运行结果: 

        =====back Refenences:======
        true

        如果字符串变成1234,那么返回的结果就是ifalse了

        System.out.println("=====back Refenences:======");
        Pattern p110 = Pattern.compile("(\d\d)\1");
        String str110 = "1234";
        Matcher m110 = p110.matcher(str110);
        System.out.println(m110.matches());

        运行结果:

        =====back Refenences:======
        false

        \1表示的是和第一组的内容一样. 1表示的是第一组.

        下面看看有多个组的案例

        /**
         * back Refenences:向前引用
         * "(\d(\d))\2" : 正则表达式的含义, 有两个组, 后面的内容和第二组的内容保持一致
         */
        System.out.println("=====back Refenences:======");
        Pattern p110 = Pattern.compile("(\d(\d))\2");
        String str110 = "122";
        Matcher m110 = p110.matcher(str110);
        System.out.println(m110.matches());

        运行结果

        =====back Refenences:======
        true
      • (?i): 忽略大小写
        /**
         * (?i) : 忽略大小写
         * 我们之前说过忽略大小写的写法是: Pattern.compile("java",Pattern.CASE_INSENSITIVE);
         * Pattern.CASE_INSENSITIVE表示忽略大小写. 我们还可以使用(?i)来表示
         */
        Pattern pp = Pattern.compile("(?i)java");
        String ss = "java Java JAva javA";
        Matcher mm = pp.matcher(ss);
        System.out.println(mm.replaceAll("JAVA"));

        运行结果

        JAVA JAVA JAVA JAVA
  • 相关阅读:
    jquery弹窗居中-类似alert()
    php explode时间分割
    php+mysql+jquery日历签到
    php查找字符串中第一个非0的位置截取
    SQL Server Data Tool 嘹解(了解)一下 SSDT -摘自网络
    Headless MSBuild Support for SSDT (*.sqlproj) Projects [利用msbuild自动化部署 .sqlproj]- 摘自网络
    SSDT – Error SQL70001 This statement is not recognized in this context-摘自网络
    Web Services and C# Enums -摘自网络
    Excel中VBA 连接 数据库 方法- 摘自网络
    解决 Provider 'System.Data.SqlServerCe.3.5' not installed. -摘自网络
  • 原文地址:https://www.cnblogs.com/ITPower/p/8718749.html
Copyright © 2020-2023  润新知