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.代码统计

Java与正则表达式Java与正则表达式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) 也可以启用不区分大小写的匹配”。

 

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

上一篇:技术人具备“结构化思维”意味着什么?


下一篇:新手如何选择阿里云服务器配置