Java正則表達式詳解+練習
一、導讀
正則表達式,又稱規則表達式。(英文名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正則表達式詳解+練習