1、正則表達式
在開發中,通常很多數據都會使用String類存儲。原因:操作字符串的功能比較多,比較方便。
在操作String類對象時,會經常遇到對字符串進行驗證的功能,而按照我們之前學習的String類,我們使用String類中的諸多函數是可以完成對字符串校驗功能的,但是代碼相對來說比較麻煩,所以在Java中引入正則表達式的概念來解決上述問題,即簡化代碼。
正則表達式:專門用于操作字符串的技術,并且可以簡化代碼,用于對字符串的復雜操作。
正則表達式弊端:代碼可讀性比較差。
1.1、案例引入
需求:驗證QQ號碼是否合法。
分析:
1、第一位不能是零;
2、QQ號碼在5到12之間(包含);
3、QQ號碼都是由數字組成;
步驟:
1)定義一個RegexDemo類,在這個類中定義一個主函數main和一個自定義函數method_1;
2)在main函數中調用自定義函數method_1;
3)在自定義函數method_1中定義一個字符串變量QQ,并賦值為12345;
4)使用if-elseIf-else結構對字符串QQ分別按照上述給定的三個條件進行判斷;
5)使用String類中的charAt()函數獲取字符串QQ中的第一個字符和字符0進行比較,相等則告訴用戶不能以0開始;
6)使用String類中的length()函數獲得字符串QQ的長度,判斷是否在5~12之間;
7)驗證字符串QQ中是否都是數字,使用Long.parseLong(QQ)把一個字符串轉成 long 類型的數據,此函數容易發生異常,所以使用try-catch代碼塊對該代碼進行捕獲異常處理;
package xuexi.a_regex_demo;
/*
* 需求:驗證QQ號碼是否合法。
分析:
1、第一位不能是零;
2、QQ號碼在5到12之間(包含);
3、QQ號碼都是有數字組成;
*/
public class RegexDemo {
public static void main(String[] args) {
method_1();
}
private static void method_1() {
// 定義一個字符串變量
String QQ = "12345676";
/*
* 使用判斷結構判斷字符串是否合法
*/
// 判斷字符串的第一位是否是0 QQ.charAt(0)表示通過charAt函數根據指定的下標獲取下標對應的字符
if (QQ.charAt(0) == '0') {
// 說明字符串以0開始
System.out.println("QQ號碼不能以0開始");
} else if (QQ.length() < 5 || QQ.length() > 12) {
// 說明qq的號碼的長度不在5~12之間
System.out.println("QQ號碼的長度錯誤");
} else {
/*
* 說明QQ的號碼一定不是以0開始,并且長度一定在5~12之間,接下來驗證是否為數字
* 使用包裝類Long中的parseLong()函數判斷字符串中的字符是否為數字
* 如果不為數字,這個函數會拋異常alt+shift+z寫try-catch代碼塊
*/
try {
long parseLong = Long.parseLong(QQ);// 將字符串轉換為long類型的數字
System.out.println("QQ號碼是:" + QQ);
System.out.println("QQ號碼是:" + parseLong);
} catch (NumberFormatException e) {
System.out.println("QQ號碼中有其他非數字的字符");
}
}
}
}
說明:
1)使用包裝類Long中的parseLong()函數判斷字符串中的字符是否為數字。如果不為數字,這個函數會拋異常,既然要拋異常所以寫個try-catch代碼塊對異常進行處理;
2)對某塊代碼進行try-catch處理,可以按alt+shift+z快捷鍵生成try-catch代碼塊;
在開發中字符串是我們使用頻率最高的一類數據,針對上述程序僅僅就是為了驗證一個字符串中的數據是否正確,用上述代碼能夠解決問題,但是代碼很麻煩。在計算機語言中針對這類數據的驗證和其他操作給出了更加簡單的處理方案。
這個方案就是正則表達式。正則表達式它的存在就是用來簡化代碼的書寫,方便完成對字符串的操作。
說明:
1、String類中提供一個matches()函數,可以判斷字符串對象是否匹配正則表達式。
1)如果匹配,則返回true;
2)如果不匹配,則返回false;
2、 [1-9]:表示字符串中第一位能夠出現1~9任何一個數字;
3、 [0-9]{4,11}:表示字符串中從第2位開始后面的數字只能出現0~9之間的數字,并且最少出現4次,最多出現11次;
4、 如果滿足上述條件則返回true,否則返回false
將上述代碼進行優化,結果如下:
package xuexi.a_regex_demo;
/*
* 需求:驗證QQ號碼是否合法。
分析:
1、第一位不能是零;
2、QQ號碼在5到12之間(包含);
3、QQ號碼都是有數字組成;
*/
public class RegexDemo {
public static void main(String[] args) {
method_2();
}
// 使用正則表達式完成QQ號碼的驗證
private static void method_2() {
// 定義一個字符串變量
String QQ = "12345";
/*
* String類中提供一個matches()函數,可以判斷字符串對象是否匹配正則表達式
* 如果匹配,則返回true
* 如果不匹配,則返回false
* [1-9]:表示字符串中第一位能夠出現1~9任何一個數字
* [0-9]{4,11}:表示字符串中從第2位開始后面的數字只能出現0~9之間的數字,并且最少出現4次,最多出現11次
* 如果滿足上述條件則返回true,否則返回false
*/
boolean flag = QQ.matches("[1-9][0-9]{4,11}");
System.out.println(flag);
}
}
總結:正則表達式其實就是通過一些符號簡化了代碼的書寫,其實底層對應的還是代碼,只不過是不用我們程序員來書寫代碼,我們只需要書寫正則表達式即可完成相應的功能。
正則表達式的弊端:符號越多,閱讀性越差。
所以要想學習正則表達式就得先學習一些符號。
1.2、正則表達式介紹
正則表達式:正確的規則組成的一個表達式。其實就是用來簡化字符串的操作。通過一些限定符號組成一種規則,來驗證字符串是否符合規則
它的功能主要是用來對字符串進行各種的操作(驗證、匹配、切割、替換,獲取等)。
結論:正則表達式只能使用在字符串上。
學習正則表達式:主要是學習正則表達式中的常用符號。
正則表達式:它是用我們所熟悉的 大括號、中括號 、小括號、字母 、數字、特殊符號等代替Java代碼對字符串進行操作。
1.3、正則表達式常用符號介紹(掌握)
在api中有正則表達式的符號介紹:
我們使用正則表達式其中一個重要的功能就是驗證字符串中每個字符是否正確:
學習怎么寫一個正則表達式去匹配(驗證)字符串的每一位。
正則表達式符號介紹:正則表達式一般也需要使用字符串進行展示:
1、一般符號
x: 指的是普通字符,x代表的是未知數,代表著任何一個普通字符,舉例x可以代表a,也可以代表b,同時也可以代表c等普通字符。
舉例說明:"a[1-9][0-9]{4,11}"這里所寫的a就是普通字符x中的一種,這時x就代表a,那么也就是說此正則表達式的第一位只能是普通字符a;
\ : 表示反斜線 例:“\” 在正則中就是“\”
\t :制表符。相當于tab鍵。
2、給出某個位置上可以出現的多個字符
[ ]表示范圍的意思。表示某一位上可以出現的字符數據,如果正則中需要匹配的某個字符串中某一位上的字符是唯一的,這時可以省略中括號。[]還有一個意思,在正則中還可以表示轉義。
[abc] 表示要么是a要么是b還可以是c(只能是其中任意一個)
例:”NBA” 正則:”N[ABC]A” 匹配正確:NBA NAA NCA
[^abc] 當前要匹配的某個字符串中的某一位上不能是a或b 或c(除了a,b,c都可以)
[a-z] 表示26個小寫字母
[A-Z] 表示26個大寫字母
[a-zA-Z] 表示26個大小寫字母
[a-d[m-p]] 當前要匹配的某個字符串中的某一位上 可以是a -d 或 m - p 的字符
[a-d&&[d-f]] 表示只能是d。必須在兩個范圍中都要符合。(交集)
[a-d&&[^d-f]] 表示只能是a,b,c
[a-z&&[^xyz]] 表示只能是除去x,y,z后的所有小寫字母
[0-9] 表示0~9之間任意數字
3、提前定義好的一些符號,可以代替上述的[]書寫的范圍
·點 表示當前需要匹配的字符串位置上可以是任意的字符。例:以a開始后面可以是任意字符 “a.”
\d 表示數字。[0-9] 例:“A[\d]C” 表示A和C之間可以任意的0~9之間的數字。
說明:為什么在上述正則表達式“A[\d]C”中書寫\d,而不是直接書寫\d呢?
\d 代表著正則表達式中的一個符號,\和d放在一起代表0~9的十個數字。一旦將\d書寫在””雙引號中作為字符串,會出現一個問題,\就會把這個d轉義了,一旦轉義就不表示\d是一起的了,那怎么解決這種問題呢?
我們應該在\d前面在加一個,如:\d,第一個 \ 表示將第二個 \ 轉義成普通的反斜線字符,而變成普通的反斜線之后和d組合就代表著正則中的數字,所以我們需要這樣寫:”\d” 等同于”[0-9]”
\\ 反斜線字符
\D 表示非數字。[^0-9]
\w 表示[a-zA-Z_0-9]</tt>。可以是任意數字、任意大小寫字母、下劃線。
\W 表示[^a-zA-Z_0-9]表示和\w相反。
4、邊界匹配
^ 表示行的開頭 例:“^h.” 表示只能是以h作為開頭
$ 表示行的結尾 例:”^h.o$” 表示只能以h作為開頭,以o作來結尾
5、數量詞:表示當前正則表達式中某個規則可以出現的次數。注意:數量詞前面必須有存在正則符號。
“A?” 表示當前需要匹配字符串這個位置開始往后大寫字母A可以出現零次或一次;
舉例:”[0-9]?”表示在當前的字符串位置上0~9之間的任何一個數只能出現零次或者一次;
“A*” 表示當前需要匹配字符串這個位置開始往后大寫字母A可以出現零次或多次;
舉例:”[0-9]*”表示在當前的字符串位置上0~9之間的任何一個數可以出現零次或者一次或者多次;
“A+” 表示當前需要匹配字符串這個位置開始往后大寫字母A可以出現一次或多次;
舉例:”[0-9]+”表示在當前的字符串位置上0~9之間的任何一個數可以出現一次或者多次;
“A{n}”----> “A{10}” 表示當前需要匹配字符串這個位置開始往后大寫字母A必須出現10次;
舉例:”[0-9]{10}”表示在當前的字符串位置上0~9之間的任何一個數可以出現10次;
“A{n,}----->”“A{10,}”表示當前需要匹配字符串這個位置開始往后大寫字母A最少出現10次;
舉例:”[0-9]{10,}”表示在當前的字符串位置上0~9之間的任何一個數最少出現10次;
“A{n,m}”---->“A{10,20}”表示當前需要匹配字符串這個位置開始往后大寫字母A最少出現10次,最多20次;
舉例:”[0-9]{10,20}”表示在當前的字符串位置上0~9之間的任何一個數最少出現10次,最多20次;
1.4、正則的功能介紹(掌握)
正則表達式的主要功能:
它主要是用來對字符串進行操作:匹配(驗證)、切割、替換、獲取。
正則表達式需要和String類中的某些函數結合使用。
1.4.1、匹配
根據指定的正則表達式匹配字符串,匹配正確返回的是true,匹配錯誤,返回false。
需求:驗證手機號碼
分析:手機號碼的規則:
1)長度必須是11位;
2)第一位只能是數字1;
3)第二位可以是3 4 5 7 8;
4)從第三位開始可以是0-9
步驟:
1)定義一個RegexDemo1類,在這個類中定義一個主函數main;
2)在main函數中定義一個String類型的變量tel,并賦值為15066668888;
3)定義一個手機號碼的正則規則regex=”1[34578][0-9]{9}”;
4)使用字符串變量tel調用String類中的matches()函數,regex正則規則作為參數進行傳遞,打印結果;
package xuexi.a_regex_demo;
/*
* 需求:驗證手機號碼
分析:手機號碼的規則:
1)長度必須是11位;
2)第一位只能是數字1;
3)第二位可以是3 4 5 7 8;
4)從第三位開始可以是0-9
*/
public class RegexDemo1 {
public static void main(String[] args) {
// 定義一個字符串
String tel = "15066668888";
// 定義一個手機號的正則
String regex = "1[34578][0-9]{9}";
// 使用字符串對象tel調用String類中的matches函數,判斷字符串是否匹配正則表達式
System.out.println(tel.matches(regex));
}
}
1.4.2、切割
需求:使用String類中的split函數根據正則表達式規則,以數字對已知的字符串進行切割。
1)定義RegexDemo2 類;
2)在這個類中定義一個字符串str,并賦值為”sfajs12321dbfj234d23sjfk454sdjf565sdhd757hf”;
3)定義一個正則表達式規則:regex=”\d+”;
4)使用定義好的字符串str調用split()函數對正則表達式進行切割;
5)遍歷切割后的數組;
package xuexi.a_regex_demo;
/*
* 需求:使用String類中的split函數根據正則表達式規則,以數字對已知的字符串進行切割。
1)定義RegexDemo2 類;
2)在這個類中定義一個字符串str,并賦值為”sfljs12321dlfj234d23sjfk454sdjf565sdhd757hf”;
3)定義一個正則表達式規則:regex=”\\d+”;
4)使用定義好的字符串str調用split()函數對正則表達式進行切割;
5)遍歷切割后的數組;
*/
public class RegexDemo2 {
public static void main(String[] args) {
// 定義一個字符串
String str = "sfajs12321dbfj234d23sjfk454sdjf565sdhd757hf";
// 定義一個正則表達式,以數字對上述字符串進行切割{"sfajs","dbfj","d","sjfk"}
String regex = "\\d+";
String[] strs = str.split(regex);
// 遍歷數組
for (int i = 0; i < strs.length; i++) {
// 打印數組中的數據
System.out.println(strs[i]);
}
}
}
需求:使用String類中的split函數根據正則表達式規則,以疊詞對已知的字符串進行切割。
疊詞:就是重復出現的字符。
1)在RegexDemo2類中定義一個method_2函數;
2)在method_2函數中定義一個字符串str,并賦值為
”sfljs#######lfj234#######k454sd#####sdhd######hf”;
3)定義一個正則表達式規則:regex=”#+”;
4)使用定義好的字符串str調用split()函數對正則表達式進行切割;
5)遍歷切割后的數組;
public class RegexDemo2 {
public static void main(String[] args) {
method_2();
}
//以同一個疊詞 切割
public static void method_2() {
String str = "sfljs#######lfj234#######k454sd#####sdhd######hf";
String regex = "#{2,}";
String[] split = str.split(regex);
for (int i = 0 ; i<split.length ; i++) {
System.out.println(split[i]);
}
}
1.4.3、正則中的組
需求:以疊詞對已知字符串”sfljs####lfj234TTTTTTTk454sdOOOOOOOsdhd11111111hf”進行切割。
分析:這個字符串不再像我們之前做過的字符串,他比較特殊,我們之前的疊詞都是一樣的字符,而這個疊詞中的字符都不相同,如果按照我們之前去切割是不能夠實現的,那么我們該如何去切割已知的字符串呢?
我們需要借助正則中的組來完成。
正則中組的概念:
組:把已經存在的一個正則規則使用小括號封裝起來,當在正則表達式中的其他位置上需要使用
已經存在的正則規則的時候,這時沒有必要再書寫重復的規則,而直接去引用被封裝好的正則規則。
例如:"([a-z_A-Z])bc[a-z_A-Z]"
上述正則表達式:在第一位和第四位上是相同的正則規則,同一正則表達式中不同位置上存在了相同規則的正則,在書寫上重復沒有必要。我們可以在正則表達式中的第一個位置上把[a-z_A-Z] 這個規則進行封裝到一個組中。然后在正則的第四位上需要使用和第一位上相同的規則即可。 這時可以在第四位上引用這個被封裝好的組。
在正則中一旦把某個規則使用小括號封裝成組之后,由于我們只能使用小括號進行組的封裝,而無法給組起名,這時會自動的給這些組進行編號,組的編號從1開始,一個小括號就是一組。
如果在當前分組的這個正則表達式中引用已經存在的組,需要使用\\組的編號
例如:"([a-z_A-Z])bc\\1"
需求:使用String類中的split函數根據正則表達式規則,以疊詞對已知的字符串進行切割。(練習正則表達式中的組的概念)
1)在RegexDemo2類中定義一個method_3函數;
2)在method_3函數中定義一個字符串str,并賦值為
”sfljs####lfj234TTTTTTTk454sdOOOOOOOsdhd11111111hf”;
3)定義一個正則表達式規則:regex=”(.)\1+”;
4)使用定義好的字符串str調用split()函數對正則表達式進行切割;
5)遍歷切割后的數組;
需求:電子郵箱匹配的練習;
分析:
1)電子郵箱的@符號是固定的,前面是用戶名,后面是一般公司的域名信息;
2)用戶名可以是數字 字母 下劃線;
3)公司域名可以是數字 字母;
步驟:
1)定義RegexDemo3類;
2)在這個類中定義一個字符串email,并賦值為”heixuanfeng@163.com”;
3)定義一個正則表達式規則:
regex=”[0-9a-zA-Z_]+@[0-9a-zA-Z]+(\.[a-zA-Z]+){1,3}”;
4)使用字符串對象email調用String類中的matches函數,regex作為正則表達式規則,并打印結果;
package xuexi.a_regex_demo;
public class RegexDemo3 {
public static void main(String[] args) {
//定義一個字符串
String str="heixuanfeng@163.com.cn";
//定義一個正則表達式來驗證郵箱
//(\\.[a-zA-Z]+){1,3}表示.com.cn可以出現1到3次
String regex="\\w+@[0-9a-zA-Z]+(\\.[a-zA-Z]+){1,3}";
System.out.println(str.matches(regex));
}
}
1.4.4、替換
案例1:替換的簡單應用
需求:
1)定義一個RegexDemo4類,在這個類中定義一個main函數;
2)在main函數中定義一個字符串str,并賦值為hello world;
3)使用str字符串對象調用String類中的replaceAll()函數將字符串中的l替換為i,并重新生成一個字符串,并打印;
案例2:把字符串中的所有#號變為-號,最后變成一個-
需求:
1)在RegexDemo4類中定義一個method_2函數;
2)在method_2函數中定義一個字符串str,并賦值為
“sdhf#jksdhf1232###j45k45dsh54######65f765j#######7kd”;
3)使用str字符串對象調用String類中的replaceAll()函數將字符串中所有的#替換為-,并重新生成一個字符串,并打印;
案例3:把字符串中的多個相同字符,替換成一個字符
原字符串:“abc###nbaAAAAAAsh000000xuexi#####cbaXXXXXXcom”
替換后:” abc#nbaAsh0xuexi#cbaXcom
說明:
前面學習了在一個正則表達中使用前面已經封裝的正則規則,使用\組號引用
如果需要在其他地方引用正則中的組,這里需要使用 $組號。
需求:
1)在RegexDemo4類中定義一個method_3函數;
2)在method_3函數中定義一個字符串str,并賦值為
“abc###nbaAAAAAAsh000000xuexi#####cbaXXXXXXcom”;
3)使用str字符串對象調用String類中的replaceAll()函數將字符串中所有的多個相同的字符替換成一個字符,并重新生成一個字符串,并打印;
案例4:隱藏手機號碼中間4位 150****8888
需求:
1)在RegexDemo4類中定義一個method_4函數;
-
在method_4函數中定義一個字符串str,并賦值為”15066668888”;
3)把正則表達式分為三組,第二組使用****替換,使用str字符串對象調用String類中的replaceAll()函數將字符串中的中間四位手機號替換成****,并重新生成一個字符串,并打印;
13.png
1.4.5、獲取
需求:案例:獲取字符串中的所有手機號碼
“shshska13966668888hdjd13966668888iaj”
正則的獲取功能指的是從一個字符串中截取出來我們需要的子串。
需要學習2個對象:
1、正則表達式對象
2、匹配器對象
正則表達式對象:正則表達式是計算機語言中存在一類具備特定功能的表達式,那么Java對這類表達式使用類的描述和封裝。
正則表達式是在java中存在的一種規則,而java語言對于存在的事物,都會使用類來描述。在java.util.regex包中存在一個用來描述正則表達式的類:
通過查閱API,可以獲得:
1)Pattern類是最終的類,不能被繼承;
2)Pattern類是java中正則表達式的實例對象,而我們書寫好的一個正則表達式,被封裝成Pattern的對象之后,這時我們就可以通過對象的方式來操作正則表達式;
3)Pattern類沒有構造函數,我們不能直接new這個類的對象。一般不能new對象的類,都會在這個類中給我們提供靜態的函數,獲取本類的對象。所以需要使用compile()方法獲取Pattern類實例;
4)先要有Pattern類的實例(正則表達式的實例對象),通過實例對象創建匹配器對象(Matcher類),最后是使用匹配器對象中的matcher方法來對正則進行驗證;
就可以把一個字符串形式的正則表達式,變成Pattern對象。
需求:定義一個手機號的正則表達式,使用Pattern類中的compile函數將定義好的正則表達式編譯成正則對象。
說明:經過對正則表達式的編譯,我們就得到了一個正則對象,這個對象中封裝的就是那個正則表達式。
把正則表達式編譯成正則對象之后,這時只有一個正則對象,是無法和需要匹配或驗證的字符串進行關聯。
這時必須讓自己的正則對象和需要匹配的字符串通過中間的匹配器進行關聯,然后才能去操作。
匹配器對象:
在Pattern類中提供matcher函數,可以讓當前的正則對象與需要匹配的字符串進行關聯,然后得到一個匹配器對象,我們通過這個匹配器對象就可以去通過正則操作字符串。
案例:獲取字符串中的所有手機號碼
“shshska13966668888hdjd13966668888iaj”
步驟:
1)定義一個手機號碼的正則表達式regex=”1[34578][0-9]{9}”;
2)使用Pattern類調用Pattern類中的compile函數對上述正則表達式進行編譯生成一個正則對象p;
3)定義一個字符串str=”sdjfklsdjf13867891234ksdjfuiotk”;
4)使用正則對象p調用Pattern類matcher函數,str作為字符串,生成一個匹配器對象matcher;
5)使用匹配器對象matcher調用Matcher類中的find()函數去字符串str中查找根據指定的正則表達式的結果,找到手機號返回結果true,找不到返回false;
6)由于字符串可以有多個手機號,所以使用while循環去查找,而matcher.find()作為while循環的循環條件;
7)使用匹配器對象matcher調用Matcher類中的group()函數找出符合正則的子字符串;
說明:
1)find()表示根據正則表達式去字符串中查找,如果找到,則返回true,找不到返回false;
2)group()表示根據正則表達式去字符串中找出符合正則的子字符串;
正則對象和匹配器的使用:
1、需要把一個正則表達式,通過Pattern類中的compile函數編譯成正則對象;
2、使用Pattern類中matcher方法讓正則對象和需要操作的字符串產生關系,得到一個匹配器對象;
3、使用匹配器中的find進行匹配,使用group方法獲取到匹配到的字符串;
正則的功能:
字符串的匹配、切割、替換、獲取
正則的符號:
. 表示任意的字符
() 對已經存在的正則進行分組 同一正則引入組 \編號 ,不同 $編號
[] 某個字符串位置上可以出現的字符列表
{}當前某個正則規則出現的次數
? 表示當前的規則可以出現零次或一次
- 表示當前的規則可以出現零次或一次或多次
- 表示當前的規則可以出現一次或多次
^ 行開始
$ 行結尾
\d 數字字符 [0-9]
\w 數字 字母 下劃線[0-9a-zA-Z_]