广

Java编程

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

    Java的正则表达式深入分析

    2018-11-14 08:50:19 次阅读 稿源:互联网
    零七广告

    一.regex(正则表达式):RegularExpressions(代替了StringTokenizer);字符串处理利器;在unix流行,perl使用regex更牛。
    主要用在字符串匹配、查找和替换。例如:匹配IP(范围小于256)使用正则很好搞;从网页中揪出大量email地址发送垃圾邮件;从网页里揪出链接。包含Matcher(用模式匹配字符串后产生的结果)和pattern。
    代码如下:

     /*
              * 告知此字符串是否匹配给定的正则表达式(也是一个字符串)。
              */
             System.out.println("abc".matches("..."));//每个"."表示一个字符


    代码如下:

     /*
              * 把字符串里的所有数字替换成"-",普通方法需要charAt逐个判断;
              * "//d"表示任意一个数字或者换成"[0-9]";
              * "//D"表示任意一个非数字或者换成"[^0-9]"
              */
             System.out.println("ab54564654sbg48746bshj".replaceAll("[0-9]", "-"));//每个"."表示一个字符

    二、
    代码如下:

    /*
              * compile将给定的正则表达式编译到模式中(每次编译需要费时间);{3}表示恰好三次。
              *     X{n} X,恰好 n 次
              *    X{n,} X,至少 n 次
              *    X{n,m} X,至少 n 次,但是不超过 m 次
              */
             Pattern p = Pattern.compile("[a-z]{3}");
             Matcher m = p.matcher("ggs");//创建匹配给定输入与此模式的匹配器。内部实际上是创建了一个优先状态的自动机(编译原理)
             //matcher和matches里待匹配的字符串实际上是CharSequence(接口),不过String实现了该接口,存在多态
             System.out.println(m.matches());//若是"ggss"就不匹配了
             //可一直接"ggs".matches("[a-z]{3}"),不过上面的有好处,至少效率高了,而且Pattern和Matcher提供了很多功能

    三、在regex“. * +”中叫Meta Character;ctrl + shift + "/"表示注释,换成"/"表示去掉注释。
    代码如下:

    "a".matches(".");//true,"."表示任意一个字符,汉字也行
             "aa".matches("aa");//true,也就是说普通字符串也可以作为正则表达式
             /*
              * true,"*"表示0或者多个字符,不过后面的要和第一个相同,
              * 否则false,也就是判断字符串是否是单一字符组成的字符串
              */
             "aaaa".matches("a*");
             "".matches("a*");//true
             "aaa".matches("a?");//true,一次或者0次
             "".matches("a?");//true
             "a".matches("a?");//true
             "544848154564113".matches("//d{3,100}");//true
             //这个是最简单的IP判断,不过若是超过255则判断不出来
             "192.168.0.aaa".matches("//d{1,3}//.//d{1,3}//.//d{1,3}//d{1,3}");
             "192".matches("[0-2][0-9][0-9]");

    四、[abc]表示匹配任意一个字符;[^abc]表示出了abc以外的其他字母(必须还是字母,若是空串也返回false)字符;[a-zA-Z]等价于"[a-z]|[A-Z]"是否是某个大小写字母;[A-Z&&[ABS]]表示大写字母中取ABS中任一个。
    代码如下:

    //发现|和||没区别,&和&&有区别,不知道这么理解对不对
             System.out.println("C".matches("[A-Z&&[ABS]]"));//false
             System.out.println("C".matches("[A-Z&[ABS]]"));//true
             System.out.println("A".matches("[A-Z&&[ABS]]"));//true
             System.out.println("A".matches("[A-Z&[ABS]]"));//true
             System.out.println("C".matches("[A-Z|[ABS]]"));//true
             System.out.println("C".matches("[A-Z||[ABS]]"));//true

    五、/w 单词字符:[a-zA-Z_0-9] 进行用户名匹配时;/s 空白字符:[ /t/n/x0B/f/r]; /S 非空白字符:[^/s] ;/W 非单词字符:[^/w] 。
    代码如下:

    " /n/t/r".matches("//s{4}");//true
             " ".matches("//S");//false
             "a_8".matches("//w{3}");//true
             //“+”表示一次或者多次
             "abc888&^%".matches("[a-z]{1,3}//d+[&^#%]+");//true
             /*
              * 待匹配字符也只是一个反斜线,不过不可写成"/"那么和后面的"组合了,
              * 前面的"无法匹配就会CE。
              * 后面不可写成"//",那么会运行错误(编译没问题),必须写成"////"
              */
             System.out.println("//".matches("////"));//true

    六、POSIX 字符类(仅 US-ASCII)
    代码如下:

     /p{Lower} 小写字母字符:[a-z] ;/p{Upper} 大写字母字符:[A-Z] ;/p{ASCII} 所有 ASCII:[/x00-/x7F] ;/p{Alpha} 字母字符:[/p{Lower}/p{Upper}] ;/p{Digit} 十进制数字:[0-9] 。

    七、边界匹配器
    ^ 行的开头
      $ 行的结尾
      /b 单词边界
      /B 非单词边界
      /A 输入的开头
      /G 上一个匹配的结尾
      /Z 输入的结尾,仅用于最后的结束符(如果有的话)
      /z 输入的结尾
    代码如下:

    "hello world".matches("^h.*");//^行的开头
             "hello world".matches(".*ld$");//$行的结尾
             "hello world".matches("^h[a-z]{1,3}o//b.*");///b单词边界
             "helloworld".matches("^h[a-z]{1,3}o//b.*");

     " /n".matches("^[//s&&[^//n]]*//n$");//判断空白行,空白行开头是空白符

    八、还可以在find方法下使用m.start()和m.end()返回开始位置和结束位置的下一个;若是找不到则出错。
    代码如下:

    Pattern p = Pattern.compile("//d{3,5}");
             String s = "133-34444-333-00";
             Matcher m = p.matcher(s);
             m.matches();//matches匹配全部字符串
             m.reset();
             /*
              * 下面若是先调用了reset方法则输出true,true,true,false.
              * 否则倒数第二个find也输出false。
              * 原因如下:
              * matches匹配到第一个"-"发现不匹配了,但是这四个字符已经被吃掉啦,再次匹配就从
              * 34444开始了,第二个find从333,因为find匹配的是下一个子序列。
              * reset方法让matches吃掉的字符串再吐出来。
              * 综上:matches和find之间要使用reset,因为二者相互影响
              *
              */
             m.find();
             m.find();
             m.find();//尝试查找与该模式匹配的输入序列的下一个子序列
             m.find();
             /*
              * 尝试将从区域开头开始的输入序列与该模式匹配。
              * Thinking in java的作者狠狠滴批评了这个方法,因为从字面看不出来到底从哪开始匹配。
              * 下面全部是true,因为每次都从头开始
              */
             m.lookingAt();
             m.lookingAt();
             m.lookingAt();
             m.lookingAt();

    九、字符串替换
    代码如下:

    import java.util.regex.Matcher;
     import java.util.regex.Pattern;

     public class TestRegexReplacement {

         public static void main(String[] args) {

             Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE);//后面的参数是整形,表示“大小写不敏感”
             Matcher m = p.matcher("Java java hxsyl Ilovejava java JaVaAcmer");
             while(m.find()) {
                 System.out.println(m.group());//m.group会输出所有的java(忽略大小写)

             }

            
             String s = m.replaceAll("Java");//String也有该方法
             System.out.println(s);

             m.reset();//一定要加,因为find和matcher相互影响
             StringBuffer sb = new StringBuffer();
             int i = 0;
             /*
              * 下面的方法是把找到的奇数个java替换为“Java”,偶数个替换成"java"
              */
             while(m.find()) {
                 i++;
                 //不能直接写成i&1必须转化为boolean
                 if((i&1)==1) {
                     m.appendReplacement(sb, "Java");
                 }else {
                     m.appendReplacement(sb, "java");
                 }
             }

             m.appendTail(sb);//把找到的最后一个java后边的剩余字符串加上
             System.out.println(sb);//不加reset的话只输出了Acmer
         }
     }

    十、分组
    代码如下:

    /*
              * 分别加上小括号,不算最外边的大括号,第一个左括号便是第一组
              */
             Pattern p = Pattern.compile("(//d{3,5})([a-z]{2})");
             String s = "123aaa-77878bb-646dd-00";
             Matcher m = p.matcher(s);
             while(m.find()) {
                 System.out.println(m.group());
                 System.out.println(m.group(1));//输出每对符合的 数字
                 System.out.println(m.group(2));//输出每对符合的 字母
             }

    十一、抓取网页中的email
    代码如下:

    import java.io.BufferedReader;
     import java.io.FileNotFoundException;
     import java.io.FileReader;
     import java.io.IOException;
     import java.util.regex.Matcher;
     import java.util.regex.Pattern;

     /*
      * 需要什么养的方法的话先些方法名
      * 然后ctrl + 1列出推荐,系统创建该方法
      */
     public class EmailSpider {

         public static void main(String[] args) {
             // TODO Auto-generated method stub
             try {
                 BufferedReader br = new BufferedReader(new FileReader("F://regex.html"));
                 String line = "";
                 try {
                     while((line=br.readLine())!=null) {
                         solve(line);
                     }
                 } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }

             } catch (FileNotFoundException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }

     
         }

         private static void solve(String line) {
             // TODO Auto-generated method stub
             //正则表达式要是不满足相应功能的话不会出错,因为他是字符串
             Pattern p = Pattern.compile("[//w[.-]]+@[//w[.-]]+//.[//w]+");
             Matcher m = p.matcher(line);

             while(m.find()) {
                 System.out.println(m.group());
             }

         }

     }

    十二、代码统计
    代码如下:

    View Code
     /*
      * 统计代码里多少空行,注释行,程序行
      * 实际上使用String里的startsWith和endsWith也行.
      * 若是项目经理用的话还要统计每行的字符数是否以{;结尾,防止偷懒
      */
     import java.io.BufferedReader;
     import java.io.File;
     import java.io.FileNotFoundException;
     import java.io.FileReader;
     import java.io.IOException;

     public class CoderCount {

         static long normalLines = 0;
         static long commentLines = 0;
         static long whiteLines = 0;

         public static void main(String[] args) {
             File f = new File("D://share//src");
             File[] codeFiles = f.listFiles();
             for(File child : codeFiles){
                 if(child.getName().matches(".*//.java$")) {
                     solve(child);
                 }
             }

             System.out.println("normalLines:" + normalLines);
             System.out.println("commentLines:" + commentLines);
             System.out.println("whiteLines:" + whiteLines);

         }

         private static void solve(File f) {
             BufferedReader br = null;
             boolean comment = false;
             try {
                 br = new BufferedReader(new FileReader(f));
                 String line = "";
                 while((line = br.readLine()) != null) {
                     /*
                      * //有的注释行前面有一个tab
                      * 不可写在readLine后
                      * 最后一行的话会空指针
                      */
                     line = line.trim();
                     //readLine读出字符串后就把后面的换行去掉啦
                     if(line.matches("^[//s&&[^//n]]*$")) {
                         whiteLines ++;
                     } else if (line.startsWith("/*") && !line.endsWith("*/")) {
                         commentLines ++;
                         comment = true;   
                     } else if (line.startsWith("/*") && line.endsWith("*/")) {
                         commentLines ++;
                     } else if (true == comment) {
                         commentLines ++;
                         if(line.endsWith("*/")) {
                             comment = false;
                         }
                     } else if (line.startsWith("//")) {
                         commentLines ++;
                     } else {
                         normalLines ++;
                     }
                 }
             } catch (FileNotFoundException e) {
                 e.printStackTrace();
             } catch (IOException e) {
                 e.printStackTrace();
             } finally {
                 if(br != null) {
                     try {
                         br.close();
                         br = null;
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
                 }
             }
         }

     }

    十三、Quantifiers
    包括?*+;默认全是Greedy,还有Reluctant和Possessive(独占性的)。
    代码如下:

    //加上分组是为了看得更清晰一些
         Pattern p = Pattern.compile("(.{3,10})+[0-9]");
         String s = "aaaa5bbbb6";//长度是10
         Matcher m = p.matcher(s);
         /*
          * 现在输出0-10,默认是Greedy,先吞进10个字符,发现不匹配,吐出来一个,发现匹配了;
          * 若是Pattern.compile("(.{3,10}?)+[0-9]")则成了Reluctant,那么是先吞进三个字符,发现不匹配,继续吞入 知道匹配,输出0到5;
          * 若是Pattern.compile("(.{3,10}++)+[0-9]")则是Possessive(独占式),也是先吞入10个字符,但是不向外吐,那么就不匹配了,
          * 这种方式主要用在需要高效率的地方(会有误差)。
          */
         if(m.find()) {
             System.out.println(m.start() + "----" + m.end());
         }else {
             System.put.println("Not match!");
         }

    十四、补充(非捕获组)
    代码如下:

    //非捕获组的意思和字面相反,意思是若是符合则捕获
         Pattern p = Pattern.compile("(?=a).{3}");
         /*
          * 输出a66,相当于要求以a开头,也可以这么写Pattern.compile("[a].{2}");
          * 若是Pattern.compile(".{3}(?!=a)")不是不以a结尾{2}[^a],而是下一个字符不是a(lookahead),输出44a,66b,所以这种用法不常用;
          * 若是Pattern.compile(".{3}(?=a)")则输出444(因为?=a是lookahead),放在前面则包含在组内,后面则不包含在组内;
          *
          *
          */
         String s = "444a66b";
         Matcher m = p.matcher(s);
         while(m.find()) {
             System.out.println(m.group());
         }

    十五、Back Reference
    代码如下:

    Pattern p = Pattern.compile("(//d//d)//1");
         /*
          * 输出true,//1表示和第一个组的一样,若改成1213就不对了;
          * 若是Pattern.compile("(//d(//d))//2")则需改成122才对
          *
          */
         String s = "1212";
         Matcher m = p.matcher(s);
         System.out.println(m.matches());

    十六、flags的简写
    "."是不匹配换行的,记住CASE_INSENSITIVE就行了,简写“通过嵌入式标志表达式  (?i) 也可以启用不区分大小写的匹配”。

    零七网部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与零七网进行文章共享合作。

    零七广告
    零七广告
    零七广告
    零七广告