黑马程序员-Java基础、正则表达式

 正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作。String类里也提供了几个特殊的方法:

1.boolean matches(String regex):判断该字符串是否匹配指定正则表达式。

2.String replaceAll(String regex,String replacement):返回该字符串中所有匹配正则表达式的子串替换成replacement后的新字符串。

3.String replaceFirst(String regex,String replacement):返回该字符串中第一个匹配正则表达式的子串替换成replacement后的新字符串。

4.String[] split(String regex):根据给定正则表达式拆分该字符串后得到的字符串数组。

 上面这些特殊的方法都依赖于Java提供的正则表达式的支持,除此之外,Java提供了PatternMatcher两个类专门用于提供正则表达式支持。

创建正则表达式:

实际上正则表达式就是一个字符串模版,可以匹配一批字符串,所以创建正则表达式就是创建一个特殊的字符串,正则表达式可以使用的合法字符如下表所示:

 

 

 除此之外,正则表达式中有一些特殊字符,这些特殊字符在正则表达式中有其特殊的用途,如前面介绍的反斜线(\),如果需要匹配这些特殊字符,必须首先将这些字符转义,也就是在前面添加一个反斜线(\).正则表达式中的特殊字符如下表所示:

 

 如果使用上面多个字符拼起来,就可以创建一个正则表达式,例如:”\\u0041\\”  //匹配a\ ”\\0101\t”  //匹配a<制表符> ”\?\[”  //匹配?[   这些正则表达式依然只能匹配单个字符串,这是因为还未在正则表达式中使用“通配符”,“通配符”是可以匹配多个字符的特殊字符。正则表达式中“通配符”远远超出了普通通配符的功能,它被称为预定义字符,正则表达式支持如下表所示的预定义字符:

 

 有了上面的预定义字符后,我们就可以创建更加强大的正则表达式,例如:

  c\wt  //可以匹配catcbtcctc0t、等一批字符串。

\d\d\d-\d\d\d-\d\d\d\d //可以匹配如000-000-0000形式的电话号码。

 在一些特殊情况,例如我们只想匹配a-f的字母,或者想匹配除了ab之外的所有小写字母,或者相匹配中文字符,上面预定义字符就无能为力了,此处需要使用方括号表达式,方括号表达式有如下表所示的几种形式:

 

正则表达式还支持圆括号表达式,它用于将多个表达式组成一个子表达式,圆括号中可以使用或运算符(|),例如正则表达式”(public|protected|private)”用于匹配Java三个访问控制符其中之一。

除此之外,Java正则表达式还支持如下表所示几个边界匹配符:

 

前面例子中需要建立一个匹配000-000-0000形式的电话号码时,使用的正则表达式看起来比较繁琐。实际上,正则表达式还提供了数量标识符,正则表达式支持的数量标识符有如下几种模式:

1.Greedy(贪婪模式):除非另有表示,数量表示符默认采用贪婪模式。贪婪模式的表达式会一直匹配下去,直到无法匹配为止。如果你发现表达式匹配的结果与预期不符,很可能是因为,你以为表达式会只匹配前面的几个字符,而实际上他是贪婪模式,所以会一直匹配下去。

2.Reluctant(勉强模式):用问号后缀(?)表示,他只会匹配最少的字符。也称为最小匹配模式。

3.Possessive(占有模式):用加号后缀(+)表示,目前只有Java支持占有模式,通常比较少用。

 三种模式的数量表示符如下表所示:

 

关于贪婪模式和勉强模式的对比看如下代码:

 1 package com.king;
 2 
 3  
 4 
 5 public class TestEasy {
 6 
 7  
 8 
 9 /**
10 
11  * @author 王者黑桃
12 
13  */
14 
15 public static void main(String[] args) {
16 
17 String str="hello , world !";
18 
19 // 贪婪模式的正则表达式,将输出:0 , world !
20 
21 System.out.println(str.replaceFirst("\\w*", "0"));
22 
23 // 勉强模式的正则表达式,将输出:0hello , world !
24 
25 System.out.println(str.replaceFirst("\\w*?", "0"));
26 
27 }
28 
29  
30 
31 }

 

使用正则表达式:

一旦在程序中定义正则表达式之后,就可以使用PatternMatcher来使用正则表达式。

Pattern对象是正则表达式编译后在内存中的表示形式,因此,正则表达式字符串必须先被编译为Pattern对象,然后再利用该Pattern对象创建对应的Matcher对象。执行匹配所涉及的状态保留在Matcher对象中,多个Matcher对象可共享同一个Pattern对象。

因此,典型的调用顺序如下代码片段:

 1 //将一个字符串编译成Pattern对象
 2 
 3 Pattern p=Pattern.compile("a*b");
 4 
 5 //使用Pattern对象创建Matcher对象
 6 
 7 Matcher m=p.matcher("aaaaab");
 8 
 9 //返回true
10 
11 boolean b=m.matches();

 

上面定义的Pattern对象可以多次重复使用。如果某个正则表达式仅需一次使用,可直接使用Pattern类的静态matches方法,此方法自动把指定字符串编译成匿名的Pattern对象,并执行匹配,如下代码片段:

1 //返回true
2 
3 boolean bool=Pattern.matches("a*b", "aaaab");

 

 上面语句等效与前面的三个语句。但采用这种语句每次都需要重新编译新的Pattern对象,不能重复利用已编译的Pattern对象,所以效率不高。

Pattern是不可变类,可供多个并发线程安全使用。

Pattern类和Matcher类中看到一个CharSequence接口,该接口代表一个字符序列,其中CharBufferStringStringBufferStringBuilder都是它的实现类。简单的说,CharSequence代表各种表示形式的字符串。

Matcher类提供了如下几种常用方法:

1.find:返回目标字符串中是否包含与Pattern匹配的子串。

2.group:返回上一次与Pattern匹配的子串。

3.start:返回上一次与Pattern匹配的子串在目标字符串中的开始位置。

4.end:返回上一次与Pattern匹配的子串在目标字符串中的结束位置+1

5.lookingAt:返回目标字符串前面部分与Pattern是否匹配。

6.matches:返回整个目标字符串与Pattern是否匹配。

7.reset:可以将现有的Matcher对象应用于一个新的字符串序列。

 通过Matcher类的findgroup方法可以从目标字符串中依次取出特定子串(匹配正则表达式的子串),下面例子程序示范了这种用途:

 1 package com.king;
 2 
 3  
 4 
 5 import java.util.regex.Matcher;
 6 
 7 import java.util.regex.Pattern;
 8 
 9  
10 
11 public class FindGroup {
12 
13  
14 
15 /**
16 
17  * @author 王者黑桃
18 
19  */
20 
21 public static void main(String[] args) {
22 
23 // 创建一个Pattern对象,并用它建立一个Matcher对象
24 
25 Matcher m=Pattern.compile("\\w+")
26 
27 .matcher("I like java very much !");
28 
29 while(m.find()){
30 
31 System.out.println(m.group());
32 
33 }
34 
35 System.out.println("================");
36 
37 int i=0;
38 
39 while(m.find(i)){
40 
41 System.out.print(m.group()+"\t");
42 
43 i++;
44 
45 }
46 
47 }
48 
49  
50 
51 }

 

运行上面程序将看到如下结果:

 1 I
 2 
 3 like
 4 
 5 java
 6 
 7 very
 8 
 9 much
10 
11 ================
12 
13 I like like ike ke e java java ava va a very very ery ry y much much uch ch h

 

从上面运行结果可以看出,find方法依次查找字符串中与Pattern匹配的子串,一旦找到对应的子串,下次调用find方法将接着向下查找。除此之外,find方法还可以传入一个int类型的参数,带int参数的find方法从该int索引处向下搜索。

Startend方法主要用于确定子串在目标字符串中的位置,如下程序代码所示:

 1 package com.king;
 2 
 3  
 4 
 5 import java.util.regex.Matcher;
 6 
 7 import java.util.regex.Pattern;
 8 
 9  
10 
11 public class StartEnd {
12 
13  
14 
15 /**
16 
17  * @author 王者黑桃
18 
19  */
20 
21 public static void main(String[] args) {
22 
23 // 创建一个Pattern对象,并用它建立一个Matcher对象
24 
25 String string="I like java very much !";
26 
27 System.out.println("目标字符串是:"+string);
28 
29 Matcher mt=Pattern.compile("\\w+")
30 
31 .matcher(string);
32 
33 while(mt.find()){
34 
35 System.out.println(mt.group()+"子串的起始位置:"
36 
37 +mt.start()+",子串的结束位置:"
38 
39 +mt.end());
40 
41 }
42 
43 }
44 
45  
46 
47 }

 

上面程序使用findgroup逐项取出目标字符串中与指定正则表达式匹配的子串,并使用startend方法来返回子串在目标字符串中的位置,运行结果:

 1 目标字符串是:I like java very much !
 2 
 3 I子串的起始位置:0,子串的结束位置:1
 4 
 5 like子串的起始位置:2,子串的结束位置:6
 6 
 7 java子串的起始位置:7,子串的结束位置:11
 8 
 9 very子串的起始位置:12,子串的结束位置:16
10 
11 much子串的起始位置:17,子串的结束位置:21

 

Matches和lookingAt方法有点类似,只是matches方法要求整个字符串和Pattern完全匹配时才返回true,而lookingAt只要字符串以Pattern开头就返回true。reset方法可将现有的Matcher对象应用于新的字符串序列。看如下例子程序:

 1 package com.king;
 2 
 3  
 4 
 5 import java.util.regex.Matcher;
 6 
 7 import java.util.regex.Pattern;
 8 
 9  
10 
11 public class TestMatches {
12 
13  
14 
15 /**
16 
17  * @author 王者黑桃
18 
19  */
20 
21 public static void main(String[] args) {
22 
23 String[] mails={
24 
25 "18338878315@163.com",
26 
27 "614508584@qq.com",
28 
29 "jiangyantao@abc.xx",
30 
31 "jiang1016@live.cn"
32 
33 };
34 
35 String mailRegEx="\\w{3,20}@\\w+\\.(com|org|cn|gov|net)";
36 
37 Pattern mailPattern=Pattern.compile(mailRegEx);
38 
39 Matcher mailMatcher=null;
40 
41 for(String mail:mails){
42 
43 if(mailMatcher==null){
44 
45 mailMatcher=mailPattern.matcher(mail);
46 
47 }else{
48 
49 mailMatcher.reset(mail);
50 
51 }
52 
53 if(mailMatcher.matches()){
54 
55 System.out.println(mail+"是一个有效的邮件地址!");
56 
57 }
58 
59 else{
60 
61 System.out.println(mail+"不是一个有效的邮件地址!");
62 
63 }
64 
65 }
66 
67 }
68 
69  
70 
71 }

 

输出结果为:

18338878315@163.com是一个有效的邮件地址!

614508584@qq.com是一个有效的邮件地址!

jiangyantao@abc.xx不是一个有效的邮件地址!

jiang1016@live.cn是一个有效的邮件地址!

 

上面程序创建了一个邮件地址的Pattern,接着用这个Pattern与多个邮件地址进行匹配。当程序中的Matcher为NULL时,程序调用matcher方法来创建一个Matcher对象,一旦Matcher对象被创建以后,程序调用Matcher的reset方法将该Matcher对象应用与新的字符序列。

事实上,String类里也提供了matches方法,该方法返回该字符串是否匹配指定正则表达式。如:

 

1 "18338878315@163.com".matches("\\w{3,20}@\\w+\\.(com|org|cn|gov|net)"); //返回true

 

 

 

除此之外,还可利用正则表达式对目标字符串进行分割、查找、替换等操作,看如下程序代码:

 1 package com.king;
 2 
 3  
 4 
 5 import java.util.Arrays;
 6 
 7 import java.util.regex.Matcher;
 8 
 9 import java.util.regex.Pattern;
10 
11  
12 
13 public class TestReplace {
14 
15  
16 
17 /**
18 
19  * @author 王者黑桃
20 
21  */
22 
23 public static void main(String[] args) {
24 
25 String[] msgs={
26 
27 "I like java very much",
28 
29 "and I want to join in DarkHorse Programmer",
30 
31 "I hope it will be succeed "
32 
33 };
34 
35 for(String msg:msgs){
36 
37 System.out.println(msg.replaceFirst("an\\w*", "黑桃K"));
38 
39 System.out.println(Arrays.toString(msg.split(" ")));
40 
41 }
42 
43 System.out.println("================");
44 
45 Pattern msgPattern=Pattern.compile("an\\w*");
46 
47 Matcher msgMatcher=null;
48 
49 for(int i=0;i<msgs.length;i++){
50 
51 if(msgMatcher==null){
52 
53 msgMatcher=msgPattern.matcher(msgs[i]);
54 
55 }else{
56 
57 msgMatcher.reset(msgs[i]);
58 
59 }
60 
61 System.out.println(msgMatcher.replaceAll("黑桃K"));
62 
63 }
64 
65 }
66 
67  
68 
69 }

 

输出结果为:

I like java very much

[I, like, java, very, much]

黑桃K I want to join in DarkHorse Programmer

[and, I, want, to, join, in, DarkHorse, Programmer]

I hope it will be succeed 

[I, hope, it, will, be, succeed]
================

I like java very much

黑桃K I w黑桃K to join in DarkHorse Programmer

I hope it will be succeed 

 

正则表达式是一个功能非常灵活的文本处理工具,增加了正则表达式支持后的Java,可以不再需要StringTokenizer类(也是一个处理字符串的工具,但功能远不如正则表达式强大)的帮助就可以进行复杂的字符串处理。

 

posted @ 2014-01-07 11:03  code4a  阅读(972)  评论(1编辑  收藏  举报