• Java与正则表达式


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

    1 /*
    2          * 告知此字符串是否匹配给定的正则表达式(也是一个字符串)。
    3          */
    4         System.out.println("abc".matches("..."));//每个"."表示一个字符
    1 /*
    2          * 把字符串里的所有数字替换成"-",普通方法需要charAt逐个判断;
    3          * "\\d"表示任意一个数字或者换成"[0-9]";
    4          * "\\D"表示任意一个非数字或者换成"[^0-9]"
    5          */
    6         System.out.println("ab54564654sbg48746bshj".replaceAll("[0-9]", "-"));//每个"."表示一个字符

    2.

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

    3.在regex“. * +”中叫Meta Character;ctrl + shift + "/"表示注释,换成"\"表示去掉注释。

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

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

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

    5.\w 单词字符:[a-zA-Z_0-9] 进行用户名匹配时;\s 空白字符:[ \t\n\x0B\f\r]; \S 非空白字符:[^\s] ;\W 非单词字符:[^\w] 。

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

    6.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] 。

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

    1 "hello world".matches("^h.*");//^行的开头 
    2         "hello world".matches(".*ld$");//$行的结尾 
    3         "hello world".matches("^h[a-z]{1,3}o\\b.*");//\b单词边界 
    4         "helloworld".matches("^h[a-z]{1,3}o\\b.*");
    1 " \n".matches("^[\\s&&[^\\n]]*\\n$");//判断空白行,空白行开头是空白符 

    8.

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

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

    9.字符串替换

     1 import java.util.regex.Matcher;
     2 import java.util.regex.Pattern;
     3 
     4 public class TestRegexReplacement {
     5     
     6     public static void main(String[] args) {
     7         
     8         Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE);//后面的参数是整形,表示“大小写不敏感”
     9         Matcher m = p.matcher("Java java hxsyl Ilovejava java JaVaAcmer");
    10         while(m.find()) {
    11             System.out.println(m.group());//m.group会输出所有的java(忽略大小写)
    12             
    13         }
    14         
    15         
    16         String s = m.replaceAll("Java");//String也有该方法
    17         System.out.println(s);
    18         
    19         m.reset();//一定要加,因为find和matcher相互影响
    20         StringBuffer sb = new StringBuffer();
    21         int i = 0;
    22         /*
    23          * 下面的方法是把找到的奇数个java替换为“Java”,偶数个替换成"java"
    24          */
    25         while(m.find()) {
    26             i++;
    27             //不能直接写成i&1必须转化为boolean
    28             if((i&1)==1) {
    29                 m.appendReplacement(sb, "Java");
    30             }else {
    31                 m.appendReplacement(sb, "java");
    32             }
    33         }
    34         
    35         m.appendTail(sb);//把找到的最后一个java后边的剩余字符串加上
    36         System.out.println(sb);//不加reset的话只输出了Acmer
    37     }
    38 }

    10.分组

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

    11.抓取网页中的email

     1 import java.io.BufferedReader;
     2 import java.io.FileNotFoundException;
     3 import java.io.FileReader;
     4 import java.io.IOException;
     5 import java.util.regex.Matcher;
     6 import java.util.regex.Pattern;
     7 
     8 /*
     9  * 需要什么养的方法的话先些方法名
    10  * 然后ctrl + 1列出推荐,系统创建该方法
    11  */
    12 public class EmailSpider {
    13 
    14     public static void main(String[] args) {
    15         // TODO Auto-generated method stub
    16         try {
    17             BufferedReader br = new BufferedReader(new FileReader("F:\\regex.html"));
    18             String line = "";
    19             try {
    20                 while((line=br.readLine())!=null) {
    21                     solve(line);
    22                 }
    23             } catch (IOException e) {
    24                 // TODO Auto-generated catch block
    25                 e.printStackTrace();
    26             }
    27             
    28         } catch (FileNotFoundException e) {
    29             // TODO Auto-generated catch block
    30             e.printStackTrace();
    31         }
    32         
    33 
    34     }
    35 
    36     private static void solve(String line) {
    37         // TODO Auto-generated method stub
    38         //正则表达式要是不满足相应功能的话不会出错,因为他是字符串
    39         Pattern p = Pattern.compile("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+");
    40         Matcher m = p.matcher(line);
    41         
    42         while(m.find()) {
    43             System.out.println(m.group());
    44         }
    45         
    46     }
    47 
    48 }

    12.代码统计

    View Code
     1 /*
     2  * 统计代码里多少空行,注释行,程序行
     3  * 实际上使用String里的startsWith和endsWith也行.
     4  * 若是项目经理用的话还要统计每行的字符数是否以{;结尾,防止偷懒
     5  */
     6 import java.io.BufferedReader;
     7 import java.io.File;
     8 import java.io.FileNotFoundException;
     9 import java.io.FileReader;
    10 import java.io.IOException;
    11 
    12 public class CoderCount {
    13     
    14     static long normalLines = 0;
    15     static long commentLines = 0;
    16     static long whiteLines = 0;
    17     
    18     public static void main(String[] args) {
    19         File f = new File("D:\\share\\src");
    20         File[] codeFiles = f.listFiles();
    21         for(File child : codeFiles){
    22             if(child.getName().matches(".*\\.java$")) {
    23                 solve(child);
    24             }
    25         }
    26         
    27         System.out.println("normalLines:" + normalLines);
    28         System.out.println("commentLines:" + commentLines);
    29         System.out.println("whiteLines:" + whiteLines);
    30         
    31     }
    32 
    33     private static void solve(File f) {
    34         BufferedReader br = null;
    35         boolean comment = false;
    36         try {
    37             br = new BufferedReader(new FileReader(f));
    38             String line = "";
    39             while((line = br.readLine()) != null) {
    40                 /*
    41                  * //有的注释行前面有一个tab
    42                  * 不可写在readLine后
    43                  * 最后一行的话会空指针
    44                  */
    45                 line = line.trim();
    46                 //readLine读出字符串后就把后面的换行去掉啦
    47                 if(line.matches("^[\\s&&[^\\n]]*$")) {
    48                     whiteLines ++;
    49                 } else if (line.startsWith("/*") && !line.endsWith("*/")) {
    50                     commentLines ++;
    51                     comment = true;    
    52                 } else if (line.startsWith("/*") && line.endsWith("*/")) {
    53                     commentLines ++;
    54                 } else if (true == comment) {
    55                     commentLines ++;
    56                     if(line.endsWith("*/")) {
    57                         comment = false;
    58                     }
    59                 } else if (line.startsWith("//")) {
    60                     commentLines ++;
    61                 } else {
    62                     normalLines ++;
    63                 }
    64             }
    65         } catch (FileNotFoundException e) {
    66             e.printStackTrace();
    67         } catch (IOException e) {
    68             e.printStackTrace();
    69         } finally {
    70             if(br != null) {
    71                 try {
    72                     br.close();
    73                     br = null;
    74                 } catch (IOException e) {
    75                     e.printStackTrace();
    76                 }
    77             }
    78         }
    79     }
    80 
    81 }

    13.Quantifiers

      包括?*+;默认全是Greedy,还有Reluctant和Possessive(独占性的)。

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

    14.补充(非捕获组)
      这种方法比较绕,比较少用,掌握(?=a)的用法即可。

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

    15.Back Reference

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

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

    结束语:没必要专门看书,不会的话直接在网上找就好,别人问就一定要回答,正则表达式终于学完了,还是蛮有成就感的,哈哈……

  • 相关阅读:
    GridSplitterProperties
    软件趋势是什么?
    Chinaren,逐渐变为垃圾了。
    【JS】回调函数示例
    在编程的海洋里 有蟛蜞喜欢在浅滩栖居嬉戏 也有巨鲸在远洋遨游
    【JS】两个计时器的写法
    【Java/Regexp】如何把MyBatis中的占位符#{name} 或是拼接符${name}中的变量名称拿出来
    【JS】利用中国古老的天干地支给文件命名
    【JS】利用闭包自制的沙漏类
    【Java】十进制和十六进制的转换
  • 原文地址:https://www.cnblogs.com/hxsyl/p/2734611.html
Copyright © 2020-2023  润新知