1. 程式人生 > >Java正則表達式詳解+練習

Java正則表達式詳解+練習

ont 愛愛 方便 綜合 細節 moved move .... 保存

一、導讀

  正則表達式,又稱規則表達式。(英文名Regular Expression,所以代碼中常以regex、regexp、RE表示)。正則表達式簡單說就是用於操作文本數據的規則表達式,在Java中我們使用正則表達式來對字符串進行“有規則的操作”,沒理解沒關系,看下面的練習就懂了。

  正則表達式對字符串的常見操作有:字符串的匹配、切割、替換、獲取。下面我們就逐一進行練習:

二、正則表達式の規則

  既然是表達式,就具有特定的規則,所以我們先看看jdk的工具類Pattern對正則表達式的規則的描述:(較多,簡單瀏覽即可,當使用到對應的規則是來查閱即可。)

技術分享

三、字符串の匹配:matches()

  練習1:對輸入的qq號進行匹配(qq匹配規則:長度為5-10位,純數字組成,且不能以0開頭。)

  沒有學習正則表示式之前,我們需要用各種if語句來進行判斷,但現在我們可以使用則正表達式的規則來操作:

 1 package RegularExpression;
 2 
 3 public class regexTest {
 4     public static void main(String[] args) {
 5         //測試:
 6         String qq1 = "1832137835";
 7         String qq2 = "789j9371";
8 String qq3 = "22"; 9 String qq4 = "012189783"; 10 boolean b1 = isQQ(qq1); 11 boolean b2 = isQQ(qq2); 12 boolean b3 = isQQ(qq3); 13 boolean b4 = isQQ(qq4); 14 15 System.out.println(qq1+"是qq號碼嗎?"+b1); 16 System.out.println(qq2+"是qq號碼嗎?"+b2);
17 System.out.println(qq3+"是qq號碼嗎?"+b3); 18 System.out.println(qq4+"是qq號碼嗎?"+b4); 19 } 20 21 //練習1:匹配QQ號(長度為5-10位,純數字組成,且不能以0開頭) 22 public static boolean isQQ(String qq) { 23 //定義匹配規則: 24 String regex = "[1-9][0-9]{4,9}"; 25 26 //判斷是否符合規則 27 boolean b = qq.matches(regex); 28 29 return b; 30 } 31 }

   運行結果:

  技術分享

  解析:註意匹配規則被“濃縮”到了字符串regex中,我們只需要用"[1-9][0-9]{4,9}"就描述了qq的匹配規則,怎麽做到的呢?

  首先我們在匹配需要“一位一位地匹配”,qq匹配規則是第一位不能是0的純數字,所以我們用[1-9]來表示第一位的規則;接下來是第二位:隨意的數字都行,所以我們用[0-9]來表示,按照這個邏輯,當然後面的都應該是純數字即[0-9],但我們需要確定qq的長度只能是5~10,而規則裏我們用{}來表示範圍,即[0-9]{4,9}結合起來就表示:4~9個純數字。

  總的來說就是:[1-9]規定第一位只能是1~9即不為0的純數字,而[0-9]{4,9}則規定可輸入4~9個純數字,加起來剛好是:首位不為0的長度為5~10的純數字。

  上面使用的規則如[]、{}等特殊符號在標題二中都能找到,對於這些常用的符號我們記住就好。

  練習2:對輸入的電話號碼進行匹配(匹配要求:匹配成功的電話號碼位數為11位的純數字,且以1開頭,第二位必須是:3、7、8中的一位,即只匹配13*********、17*********、18*********的電話號碼)。

  解析:同練習1一樣,首先我們使用字符串regex對匹配規則進行描述,一位一位地匹配,所以,開頭必須是數字1,那麽我們可以寫[1]來表示(不過對於只有一個字符的描述,可省略[]);接下來描述第二個字符:只能是3、7、8,所以我們使用[378]來表示。然後後9位號碼只要是數字就可以了,所以我們可以用[0-9]{9}來表示。連起來就是:regex = "1[378][0-9]{9}"。

  我們用代碼來實現一下:

 1 package RegularExpression;
 2 
 3 public class regexTest {
 4     public static void main(String[] args) {
 5         //測試:
 6         String t1 = "13745678901";
 7         String t2 = "12745678901";
 8         String t3 = "121213121212";
 9         String t4 = "23333333333";
10         boolean b1 = isQQ(t1);
11         boolean b2 = isQQ(t2);
12         boolean b3 = isQQ(t3);
13         boolean b4 = isQQ(t4);
14         
15         System.out.println(t1+"是電話號碼嗎?"+b1);
16         System.out.println(t2+"是電話號碼嗎?"+b2);
17         System.out.println(t3+"是電話號碼嗎?"+b3);
18         System.out.println(t4+"是電話號碼嗎?"+b4);
19     }
20     
21     //練習2:匹配電話號嗎(以1開頭第二位必須是3/7/8的11位純數字組成)
22     public static boolean isQQ(String qq) {
23         //定義匹配規則:
24         String regex = "1[378][0-9]{9}";
25         
26         //判斷是否符合規則
27         boolean b = qq.matches(regex);
28         
29         return b;
30     }
31 }

  打印結果

  技術分享

 [一個小細節]:除了用[0-9]表示純數字還可以用\d來表示(上面規則裏有可以往上look),所以我們還可以令regex = "1[378]\\d{9}"。(在java中\需要用\來轉義,所以寫為\\d而不是\d)。

四、字符串の切割:split()

  對字符串進行切割就是對一個字符串按照某個或某些字符進行切割,從而變成若幹字符串。如“張三、李四、王五”,我們如果按照“、”來切割就變成三個字符串:“張三”,“李四”,“王五”。(切割的實質其實就是先進行字符串匹配,將匹配到的字符串“丟棄”,並將丟掉的前面部分和剩下的部分變成字符串)。

  練習1:對字符串“張三@@@李四@@王五@茅臺”進行切割,去掉@符號。

  分析:首先我們要去掉字符串中的若幹個@符號,如果只有一個@符號我們可以用直接用@來匹配,但這裏的@是不確定的,所以我們要用到規則中的:

技術分享

  所以我們用@+來表示:@這個符號至少出現一次這種情況,現在我們可以來看看具體的代碼:

 1 package RegularExpression;
 2 
 3 public class splitTest {
 4     public static void main(String[] args) {
 5         //練習1:切割字符串"張三@@@李四@@王五@茅臺".
 6         String s = "張三@@@李四@@王五@茅臺";
 7         
 8         //描述切割規則:以若幹@來切割
 9         String regex = "@+";
10         
11         //切割後的字符串數組:
12         String[] ss = s.split(regex);
13         
14         for(String string:ss){
15             System.out.println(string);
16         }
17         
18     }
19 }

  打印結果:

  技術分享

  練習2:【以疊詞切割】:如字符串"abccsasahhhz"按“疊詞”來切割就變成了“ab”,“sasa”,“z”。因為“cc”、“hhh”都是疊詞,需要切割掉。現在請將字符串“張三@@@李四¥¥王五ssssssss江流兒”按照疊詞切割。

  :關鍵點在於如何表示疊詞呢?連續出現兩個以上的相同字符即為疊詞,首先我們要表示任意字符:

技術分享

   我們使用“.”來表示任意字符,接著我們需要表示兩個這樣的字符:這裏我們需要使用到“組”的概念:

技術分享

   即使用括號:()來表示組,那麽組是幹嘛的?我們就可以 對組中的數據進行引用:那麽regex = "(.)\\1"就表示:某一字符出現了兩次(註意首先我們用(.)來表示任意字符,而\\1是對組(.)中的字符進行復用,合起來就是:兩個相同的字符),現在我們不只是需要出現兩次的字符,所以使用+號來表示出現多次,最終疊詞就表示為:regex = "(.)\\1+"。

  看具體實現代碼:

 1 package RegularExpression;
 2 
 3 public class splitTest {
 4     public static void main(String[] args) {
 5         //練習2:"張三@@@李四¥¥王五ssssssss江流兒"按疊詞切割.
 6         String s = "張三@@@李四¥¥王五ssssssss江流兒";
 7         
 8         //疊詞切割
 9         String regex = "(.)\\1+";
10         
11         //切割後的字符串數組:
12         String[] ss = s.split(regex);
13         
14         for(String string:ss){
15             System.out.println(string);
16         }
17         
18     }
19 }

  切割結果:

  技術分享

  [一個小細節]:轉義字符的使用

  對於“haha.lisi.nihao”這樣的字符串如果要用"."來切割,要怎麽辦呢?可能你會說定義regex="."不就哦了嗎?但是如果你代碼真這樣寫的話,你的輸出結果就會像你的腦海一樣“一片空白”。註意:“.”這個符號在正則表達式中是有特殊意義的:

技術分享

  這個小點可以代表任何字符,所以我們需要用轉義字符\來將“.”轉義為普通的點,所以只要把regex = "\\."即可。

五、字符串の替換:replaceAll()

  利用正則表達式進行字符串替換其實是先匹配指定字符串中的字符,然後再用自定義字符替換掉匹配到的字符串。

  練習一:將字符串“張三@@@李四YYY王五*****王尼瑪”中的疊詞替換為:“、”。

  分析:第一步是匹配疊詞:上面的練習中我們已經知道regex = "(.)\\1+"可以表示疊詞,所以第二部就可以使用replaceAll()方法進行替換了:

 1 package RegularExpression;
 2 
 3 public class replaceAllTest {
 4     public static void main(String[] args) {
 5         //練習1:將字符串“張三@@@李四YYY王五*****王尼瑪”中的疊詞替換為:“、”。
 6         String str = "張三@@@李四YYY王五*****王尼瑪";
 7         
 8         //匹配規則
 9         String regex = "(.)\\1+";
10         
11         //替換為:
12         String newStr = str.replaceAll(regex, "、");
13         
14         //替換後結果:
15         System.out.println(newStr);
16     }
17     
18 }

技術分享

  練習二:將“張三@@@李四YYY王五*****王尼瑪”中的疊詞替換為單字符,即結果為:“張三@李四Y王五*王尼瑪”。

  分析:這個練習和練習1很像,首先我們都需要匹配到疊詞,但是替換的內容卻不是固定的“、”了,我們需要將疊詞替換為它本身的字符,所以我們需要引用組的內容,我們可以使用$1來復用組中第1組的值(即疊詞的字符):

 1 package RegularExpression;
 2 
 3 public class replaceAllTest {
 4     public static void main(String[] args) {
 5         //練習2:將“張三@@@李四YYY王五*****王尼瑪”中的疊詞替換為單字符,即結果為:“張三@李四Y王五*王尼瑪”。
 6         String str = "張三@@@李四YYY王五*****王尼瑪";
 7         
 8         //匹配規則
 9         String regex = "(.)\\1+";
10         
11         //替換為:
12         String newStr = str.replaceAll(regex, "$1");
13         
14         //替換後結果:
15         System.out.println(newStr);
16     }
17     
18 }

  技術分享

六、字符串の獲取:

  正則表達式其實是封裝成了Pattern類,所以字符串的匹配、切割、替換都是調用了Pattern類中的方法。所以如果我們需要獲取指定字符串中的子串,首先同樣的我們需要進行字符串匹配,然後判斷指定字符串中是否有匹配的子串,有就獲取,沒有就獲取不到。

  獲取子串的步驟:

  1、描述要獲取的子串:匹配子串

  2、使用正則表達式的封裝類Pattern來獲取匹配器

  3、使用匹配器中的方法group()獲取字符串的匹配的子串

  練習:獲取字符串“Hi ! Don‘t be moved by yourself Fzz”中為兩個字母的單詞。即Hi、be、by。

  分析:根據上面的步驟:

  第一步,我們要對子串進行匹配,即兩個字母的單詞,字母可以用[a-zA-Z]來表示,範圍是兩個,所以regex = "[a-zA-Z]{2}"。

但這樣不夠準確,我們需要的是單詞,而不是三個字母,所以要用到“邊界匹配器”,即

技術分享

  單詞邊界:\b,所以regex = "\\b[a-zA-Z]{2}\\b"。

  然後是第二步:獲取匹配器

1 Pattern p = Pattern.compile(regex);
2 Matcher m = p.matcher(s);

  最後一步:使用匹配器來獲取匹配到的字符串

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

  我們來看看總體的實現代碼:

 1 package RegularExpression;
 2 
 3 import java.util.regex.Matcher;
 4 import java.util.regex.Pattern;
 5 
 6 public class groupTest {
 7     public static void main(String[] args) {
 8         String s = "Hi ! Don‘t be moved by yourself Fzz";
 9         
10         //1、匹配子串
11         String regex = "\\b[a-zA-Z]{2}\\b";
12         
13         //2、獲取匹配器
14         Pattern p = Pattern.compile(regex);
15         Matcher m = p.matcher(s);
16         
17         //3、使用匹配器的group()方法來獲取:(find方法是判斷是否具有匹配子串)、
18         System.out.println("”"+s+"“中的兩個字母的單詞有:");
19         while(m.find()){
20             System.out.println(m.group());
21         }
22     }
23 }

技術分享

七、進階:綜合練習

  練習一:口吃怎麽辦?需求:請將下面的字符串“我我我……我我……愛…愛愛……學…學……學編程”改為:“我愛學編程”。

  分析:首先我們可以將字符串中的“……”去掉,然後就可以將疊詞替換為單個漢字即可。

  

 1 package RegularExpression;
 2 
 3 public class test {
 4     public static void main(String[] args) {
 5         //口吃怎麽辦?將“我我我……我我……愛…愛愛……學…學……學編程”改為“我愛學編程”。
 6         String str = "我我我......我我......愛...愛愛...學...學......學編程";
 7         //1、首先去掉...(將.替換為""即可)
 8         String regex = "\\.";
 9         String str1 = str.replaceAll(regex,"");
10         System.out.println("1:"+str1);
11         //2、替代疊詞
12         regex = "(.)\\1+";
13         String str2 = str1.replaceAll(regex, "$1");
14         System.out.println("2:"+str2);
15     }
16 }

技術分享

  *練習二*:網絡爬蟲spider(專門獲取指定規則數據的程序)。需求:在某一個網頁中獲取該網頁中出現的特定信息,比如獲取該網頁中出現的郵箱地址。(其實這就是網頁爬蟲的簡單運用:獲取郵箱。)

  分析:首先我們隨便百度一個網頁吧:

技術分享

  首先我們就以第一個網頁為例:

技術分享

  我們可以看到裏面有超多的qq郵箱,現在我們就來獲取這個網頁裏的qq郵箱。

  1、首先我們要獲取這個網頁的html文檔,方便獲取其中的文字信息。現在我將這個文件保存在了本地方便操作。可以看一下用記事本打開的效果:

技術分享

  2、然後我們就需要使用IO流來讀取這個html文檔

  3、對讀取的文檔利用正則表達式規則進行特定字符串(即qq郵箱)的獲取

技術分享
 1 package RegularExpression;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.File;
 5 import java.io.FileReader;
 6 import java.io.IOException;
 7 import java.util.regex.Matcher;
 8 import java.util.regex.Pattern;
 9 
10 /*
11  * 網頁爬蟲測試:獲取某網頁中的QQ郵箱
12  */
13 public class spiderTest {
14     public static void main(String[] args) throws IOException {
15         //1、讀取網頁內容(即用IO流獲取我保存的html文檔)
16         File f = new File("tempFile\\spiderTest.html");
17         BufferedReader br = new BufferedReader(new FileReader(f));
18         
19         //2、匹配規則:qq郵箱
20         String regex = "[0-9]{5,10}@qq.com";//匹配5-10位qq號和@qq.com
21         
22         //3、開始獲取:
23         Pattern p = Pattern.compile(regex);
24         String line = null;
25         
26         while((line=br.readLine()) != null){//讀取html中的數據
27             Matcher m = p.matcher(line);    //匹配器
28             while(m.find()){
29                 System.out.println(m.group());//打印匹配到的qq郵箱
30             }
31         }
32         
33         br.close();//關閉IO流
34     }
35     
36 }
spiderTest

  這就是我們獲取到的郵箱:

  技術分享

八、總結

  正則表達式還有很多規則需要我們去深入學習,對於正則表達式,它的優點就是簡化了字符串的操作,缺點是我們需要學習這些特點的規則,而且符號過多時不方便閱讀。

Java正則表達式詳解+練習