正則表達式:
正則表達式定義了字符串的模式。
正則表達式可以用來搜索、編輯或處理文本。
正則表達式並不僅限於某一種語言,但是在每種語言中有細微的差別。
Java 正則表達式和 Perl的是最爲相似的。
java.util.regex包主要包括以下三個類:
· Pattern類:
pattern 對象是一個正則表達式的編譯表示。Pattern類沒有公共構造方法。要創建一個 Pattern對象,你必須首先調用其公共靜態編譯方法,它返回一個 Pattern對象。該方法接受一個正則表達式作爲它的第一個參數。
· Matcher類:
Matcher 對象是對輸入字符串進行解釋和匹配操作的引擎。與Pattern類一樣,Matcher也沒有公共構造方法。你需要調用 Pattern對象的 matcher方法來獲得一個 Matcher對象。
· PatternSyntaxException:
PatternSyntaxException 是一個非強制異常類,它表示一個正則表達式模式中的語法錯誤。
定義一個比較規則,用該規則去匹配想要匹配的東西,返回結果。
創建方式:
//創建正則對象
//調用靜態方法compile方法,傳參正則語句
String regex = "abcd";
String text = "++abcdabcd++";
Pattern pattern = Pattern.compile(regex);
//matcher匹配器對象
Matcher matcher = pattern.matcher(text);
進行匹配功能方法:find()查找,group()返回本次查找到的內容
注意,當find查找返回false時,再去執行group方法,就不會返回String,而是直接報錯,所以我們應該在執行group方法的時候進行一次判斷。
//進行匹配操作,返回匹配結果
//第一次默認從頭開始查找
boolean bool= matcher.find();
System.out.println(bool? "匹配成功" : "匹配失敗");
//查看匹配到的文本
String result = matcher.group();
System.out.println(result);
//第二次從上一次查找位置開始查找
bool=matcher.find();
System.out.println(bool? "匹配成功" : "匹配失敗");
//獲取匹配到的文本
result = matcher.group();
System.out.println(result);
//第三次從上一次查找位置開始查找
bool=matcher.find();
System.out.println(bool? "匹配成功" : "匹配失敗");
//獲取匹配到的文本,發現本次find查找失敗,查看group返回結果,報錯
//result = matcher.group();
//System.out.println(result);
//改造一下,我們在執行該方法時,進行一次if判斷
if(bool){
result= matcher.group();
System.out.println(result);
}
到目前爲止,以上代碼已經是查找到了末尾,如果我想再次從指定位置查找,可以執行find(int index)方法,從指定位置進行查找,則又能查找成功。
//從指定位置開始查找
bool=matcher.find(0);
//匹配成功
System.out.println("從指定位置開始匹配"+ (bool ? "匹配成功" : "匹配失敗"));
result= matcher.group();
System.out.println(result);
start()和end()方法
start():返回匹配到文本第一位所在的索引
end():返回匹配到的文本末尾之後一位的索引
//執行匹配方法
bool=matcher.find();
System.out.println("從指定位置開始匹配"+ (bool ? "匹配成功" : "匹配失敗"));
result= matcher.group();
System.out.println(result);
//查看一下匹配到文本內容的開始位置
start= matcher.start();
System.out.println("匹配到的開始位置:"+ start);
//查看一下匹配到的文本的結束位置後一位
end= matcher.end();
System.out.println("匹配到的結尾位置:"+ end);
LookingAt()方法:從被匹配文本開始進行匹配,如果開始不滿足正則表達式,則返回false,滿足返回true。
//從開始位置進行匹配:lookingAt()
regex= "abcd";
text= "sdasdfasdfasfdaabcdefg";
pattern= Pattern.compile(regex);
matcher= pattern.matcher(text);
bool= matcher.lookingAt();
//返回失敗,因爲text開頭並不是abcd
System.out.println("從開始進行匹配"+ (bool ? "匹配成功" : "匹配失敗"));
全匹配模式matcher()對整個匹配的文本進行匹配,返回布爾值:
//正則表達式匹配整個字符串
text= "abcd";
matcher= pattern.matcher(text);
bool= matcher.matches();
System.out.println("全匹配" +(bool ? "匹配成功" : "匹配失敗"));
//返回創建匹配器對象的pattern對象
Pattern pattern2 = matcher.pattern();
//比較返回的pattern2是否與創建mathcer對象的pattern一致
System.out.println((pattern== pattern2)?"與創建本matcher的對象是同一個對象":"其他對象");//true
替換第一個匹配到的內容replaceFirst:
//替換第一個匹配到的文本replaceFirst
regex= "abcd";
text= "sabcdabcdg";
pattern= Pattern.compile(regex);
matcher= pattern.matcher(text);
String rfResult = matcher.replaceFirst("替換的文本");
System.out.println("替換後的文本:"+rfResult);
Reset()重置匹配器matcher對象後,再次執行後,從開始進行匹配
//重置匹配器,返回本身對象
//執行到這一步,匹配的文本內容是:s替換的文本abcdg
boolean boo = matcher.find();//true
System.out.println("第一次查找"+boo);
boo= matcher.find();//false
System.out.println("第二次查找"+boo);
Matcher restMatcher = matcher.reset();
System.out.println("調用reset方法返回的對象其實就是本對象" + (restMatcher == matcher));
boo= matcher.find();
System.out.println("第三次查找"+boo);//true
//查看匹配器的信息,沒啥用
System.out.println(matcher.toMatchResult());
appendReplacement()使用指定字符串替換文本中匹配到的內容,並返回最後匹配到的內容之前的內容。
//appendReplacement(StringBuffersb, String replacement) 從頭開始查找並替換匹配到的內容,直到匹配到最後一位,並且將從頭到該位的內容輸入到sb中
regex= "abcd";
text= "+++++abcd+++++abcd++++";
pattern= Pattern.compile(regex);
matcher= pattern.matcher(text);
String Buffersb = new StringBuffer();
while(matcher.find()){
matcher.appendReplacement(sb,"X");
}
System.out.println("從開始替換匹配文本到結束:"+ sb);
appendTail():我們發現,使用替換方法,後面的內容沒了,那麼就可以使用該方法,將之後的內容添加到sb緩衝區中。
//appendTail將之前匹配到最後一次文本的之後內容加到sb中
matcher.appendTail(sb);
System.out.println("將之前匹配到最後一次的位置之後的文本也加入到sb中:" + sb);
接下來看一下常用的正則語句是如何使用的:
下面表格是從網上抄的,表格之後附有我敲的代碼供參考:
\ |
將下一字符標記爲特殊字符、文本、反向引用或八進制轉義符。例如,"n"匹配字符"n"。"\n"匹配換行符。序列"\\"匹配"\","\("匹配"("。 |
^ |
匹配輸入字符串開始的位置。如果設置了 RegExp 對象的 Multiline 屬性,^還會與"\n"或"\r"之後的位置匹配。 |
$ |
匹配輸入字符串結尾的位置。如果設置了 RegExp 對象的 Multiline 屬性,$還會與"\n"或"\r"之前的位置匹配。 |
* |
零次或多次匹配前面的字符或子表達式。例如,zo*匹配"z"和"zoo"。*等效於 {0,}。 |
+ |
一次或多次匹配前面的字符或子表達式。例如,"zo+"與"zo"和"zoo"匹配,但與"z"不匹配。+等效於 {1,}。 |
? |
零次或一次匹配前面的字符或子表達式。例如,"do(es)?"匹配"do"或"does"中的"do"。?等效於 {0,1}。 |
{n} |
n 是非負整數。正好匹配 n 次。例如,"o{2}"與"Bob"中的"o"不匹配,但與"food"中的兩個"o"匹配。 |
{n,} |
n 是非負整數。至少匹配 n 次。例如,"o{2,}"不匹配"Bob"中的"o",而匹配"foooood"中的所有 o。"o{1,}"等效於"o+"。"o{0,}"等效於"o*"。 |
{n,m} |
M 和 n 是非負整數,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的頭三個 o。'o{0,1}'等效於 'o?'。注意:您不能將空格插入逗號和數字之間。 |
? |
當此字符緊隨任何其他限定符(*、+、?、{n}、{n,}、{n,m})之後時,匹配模式是"非貪心的"。"非貪心的"模式匹配搜索到的、儘可能短的字符串,而默認的"貪心的"模式匹配搜索到的、儘可能長的字符串。例如,在字符串"oooo"中,"o+?"只匹配單個"o",而"o+"匹配所有"o"。 |
. |
匹配除"\r\n"之外的任何單個字符。若要匹配包括"\r\n"在內的任意字符,請使用諸如"[\s\S]"之類的模式。 |
(pattern) |
匹配 pattern 並捕獲該匹配的子表達式。可以使用 $0…$9 屬性從結果"匹配"集合中檢索捕獲的匹配。若要匹配括號字符 ( ),請使用"\("或者"\)"。 |
(?:pattern) |
匹配 pattern 但不捕獲該匹配的子表達式,即它是一個非捕獲匹配,不存儲供以後使用的匹配。這對於用"or"字符 (|) 組合模式部件的情況很有用。例如,'industr(?:y|ies)是比 'industry|industries'更經濟的表達式。 |
(?=pattern) |
執行正向預測先行搜索的子表達式,該表達式匹配處於匹配 pattern 的字符串的起始點的字符串。它是一個非捕獲匹配,即不能捕獲供以後使用的匹配。例如,'Windows (?=95|98|NT|2000)'匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。預測先行不佔用字符,即發生匹配後,下一匹配的搜索緊隨上一匹配之後,而不是在組成預測先行的字符後。 |
(?!pattern) |
執行反向預測先行搜索的子表達式,該表達式匹配不處於匹配 pattern 的字符串的起始點的搜索字符串。它是一個非捕獲匹配,即不能捕獲供以後使用的匹配。例如,'Windows (?!95|98|NT|2000)'匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。預測先行不佔用字符,即發生匹配後,下一匹配的搜索緊隨上一匹配之後,而不是在組成預測先行的字符後。 |
x|y |
匹配 x 或 y。例如,'z|food'匹配"z"或"food"。'(z|f)ood'匹配"zood"或"food"。 |
[xyz] |
字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。 |
[^xyz] |
反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain"中"p","l","i","n"。 |
[a-z] |
字符範圍。匹配指定範圍內的任何字符。例如,"[a-z]"匹配"a"到"z"範圍內的任何小寫字母。 |
[^a-z] |
反向範圍字符。匹配不在指定的範圍內的任何字符。例如,"[^a-z]"匹配任何不在"a"到"z"範圍內的任何字符。 |
\b |
匹配一個字邊界,即字與空格間的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。 |
\B |
非字邊界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。 |
\cx |
匹配 x 指示的控制字符。例如,\cM匹配 Control-M或回車符。x 的值必須在 A-Z或 a-z 之間。如果不是這樣,則假定 c 就是"c"字符本身。 |
\d |
數字字符匹配。等效於 [0-9]。 |
\D |
非數字字符匹配。等效於 [^0-9]。 |
\f |
換頁符匹配。等效於 \x0c和 \cL。 |
\n |
換行符匹配。等效於 \x0a和 \cJ。 |
\r |
匹配一個回車符。等效於 \x0d和 \cM。 |
\s |
匹配任何空白字符,包括空格、製表符、換頁符等。與 [ \f\n\r\t\v]等效。 |
\S |
匹配任何非空白字符。與 [^ \f\n\r\t\v]等效。 |
\t |
製表符匹配。與 \x09和 \cI等效。 |
\v |
垂直製表符匹配。與 \x0b和 \cK等效。 |
\w |
匹配任何字類字符,包括下劃線。與"[A-Za-z0-9_]"等效。 |
\W |
與任何非單詞字符匹配。與"[^A-Za-z0-9_]"等效。 |
\xn |
匹配 n,此處的 n 是一個十六進制轉義碼。十六進制轉義碼必須正好是兩位數長。例如,"\x41"匹配"A"。"\x041"與"\x04"&"1"等效。允許在正則表達式中使用 ASCII 代碼。 |
\num |
匹配 num,此處的 num 是一個正整數。到捕獲匹配的反向引用。例如,"(.)\1"匹配兩個連續的相同字符。 |
\n |
標識一個八進制轉義碼或反向引用。如果 \n 前面至少有 n 個捕獲子表達式,那麼 n 是反向引用。否則,如果 n 是八進制數 (0-7),那麼 n 是八進制轉義碼。 |
\nm |
標識一個八進制轉義碼或反向引用。如果 \nm 前面至少有 nm 個捕獲子表達式,那麼 nm 是反向引用。如果 \nm 前面至少有 n 個捕獲,則 n 是反向引用,後面跟有字符 m。如果兩種前面的情況都不存在,則 \nm 匹配八進制值 nm,其中 n和 m 是八進制數字 (0-7)。 |
\nml |
當 n 是八進制數 (0-3),m 和 l 是八進制數 (0-7) 時,匹配八進制轉義碼 nml。 |
\un |
匹配 n,其中 n 是以四位十六進制數表示的 Unicode 字符。例如,\u00A9匹配版權符號 (©)。 |
下面代碼是我對上表的一個簡單的練習:
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class TestRegex2{
public static void main(String[] args){
//匹配字符
String regex = "abc";
String text ="aaabcddfabcasf";
//[abc]匹配括號中一個成員
String regex = "[abc]";
String text ="afacsbdfa";
//在中括號中代表非,除了該括號字符之外任意字符
String regex = "[^abc]";
String text ="a1f-acs+bd4Wfa";
//取範圍內字符[a-zA-Z][a-z][1-9]
String regex = "[1-9a-e]";
String text ="a1f-acs+bd4Wfa";
//並集
String regex = "[a-c[f-l]]";
String text ="a1f-acs+bd4fjklWfzzzxxa";
//交集 取 a-f 和e-j 的交集 ef
String regex = "[a-f&&[e-j]]";
String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
//取a-z,不包含e-f字母
//[^e-f]:除了e、f所有的字母、數字、符號
String regex = "[a-z&&[^e-f]]";
String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
//.:任何字符
String regex = ".";
String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
//\d:數字0-9 ;\w:a-zA-Z_0-9;\s:空白字符,3個字母的大寫相當於取反
String regex = "\\d";
String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
//^:以之後的字符進行開始進行匹配,放在語句第一位
//$:行的結尾,以前面字符做匹配
String regex = "......a$";
String text ="aaa-aaa";
//匹配次數 ?:0或1次,+:1次及以上,*:0次及以上
String regex = "a+";
String text ="bbbb";
//{n}:代表前面字符出現n次,{n,}:n次及以上,{n,m}n~m次
String regex = "[1-9]\\d{17}";
String text ="112345678912345678";
//驗證QQ 5~10
String regex = "[1-9]\\d{4,9}$";
String text ="10086231231231231213231231";
//|:或者
String regex = "abc|ABC|XXX";
String text ="ABCabcadfXXXasABCdabcf";
//驗證身份證號
String regex = "[1-9]\\d{17}|[1-9]\\d{14}";
String text ="142212199812122222";
//驗證QQ號
String regex = "[1-9]\\d{4,9}";
String text ="12345";
//驗證手機號
String regex = "^1[3|5|7|8|9]\\d{9}";
String text ="15666666661";
//驗證郵箱 郵箱名爲6-20位,郵箱服務商域名2~10位,結尾只能匹配com,net,cn格式
String regex = "^\\w{6,20}@\\w{2,10}\\.com|net|cn";
String text ="[email protected]";
//驗證網址http://www.開頭,域名主體爲1-10位a-zA-Z0-9字符,結尾只能是以.com cn net org xin結尾的網址
String regex = "^http://w{3}\\.\\w{1,10}\\.com|cn|net|org|xin";
String text ="http://www.sohu.com";
//驗證賬號:a-zA-Z0-9_$,必須以字母打頭,6-16位
String regex = "^\\w[\\w|_|$|\\d]{5,15}";
String text ="httpww";
//驗證生日 格式 1999-12-12,月份不能大於12,月份中的日期不能大於31
String regex = "^[12]\\d{3}-[01]\\d-([12]\\d)|(3[01])";
String text ="1991-12-32";
//創建正則對象
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
System.out.println(matcher.matches()?"匹配成功":"匹配失敗") ;
//輸出匹配的內容
while(matcher.find()){
Stringresult = matcher.group();
System.out.println(result);
}
}
}
匹配器對象Matcher的替換方法:
//appendReplacement(StringBuffersb, String replacement) 從頭開始查找並替換匹配到的內容,直到匹配到最後一位,並且將從頭到該位的內容輸入到sb中
regex= "abcd";
text= "+++++abcd+++++abcd++++";
pattern= Pattern.compile(regex);
matcher= pattern.matcher(text);
StringBuffer sb = new StringBuffer();
while(matcher.find()){
matcher.appendReplacement(sb,"X");
}
System.out.println("從開始替換匹配文本到結束:"+ sb);
//appendTail將之前匹配到最後一次文本的之後內容加到sb中
matcher.appendTail(sb);
System.out.println("將之前匹配到最後一次的位置之後的文本也加入到sb中:" + sb);
分組語句:
//分組語句(),結合group方法,傳參獲取指定組的匹配內容
/
*如下正則語句,將會匹配text文本的前11位字符,是沒有問題的
*String regex = "至尊寶至尊小寶至尊大寶";
/
//但是,我現在加上括號以後,匹配的結果和沒有加括號一樣,都是前11位字符
String regex = "(至尊寶)(至尊小寶)(至尊大寶)";
String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
if(matcher.find ()){
Stringgroup = matcher.group();
System.out.println(group);
}
那麼,區別在哪兒?既然是分組語句,那麼我們可以從匹配器的group方法中看到區別,在api中,group是可以傳參的,傳參int類型,當傳入x數值時,那麼返回的將會是正則語句中第x個括號中的匹配內容,當傳入0時,返回整個匹配到的語句,如下案例:
//我現在加上括號以後,匹配的結果和沒有加括號一樣,都是前11位字符
String regex = "(至尊寶)(至尊小寶)(至尊大寶)";
String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
if(matcher.find ()){
//打印結果爲至尊寶
//String group = matcher.group(1);
//System.out.println(group);
//打印結果爲至尊小寶
String group = matcher.group(2);
System.out.println(group);
//打印結果爲:至尊寶至尊小寶至尊大寶
String group = matcher.group(0);
System.out.println(group);
}
注意:如果group傳入的參數的分組序號並不存在,如正則語句只分了2個組,但是group語句訪第3個子語句,就會報錯!
其實分組語句還有一個好處,就是給語句進行分組,達到優先級匹配的效果,如下是我寫的一個正則語句匹配身份證號,當然並不是那麼完美,但是可以看出,下面的分組語句也起到了優先級的效果:
String regex = "^[1-9]\\d{5}(19[0-9]{2}|200[0-9]|201[0-7])(0[0-9]|1[0-2])([012][0-9]|3[01])\\d{3}[0-9|X]";
String text ="35123429800231112X";
預測語句:
//(?:)向後匹配並將其作爲捕獲的內容
//語法解析:至尊後面只要有大寶、玉、小寶3個成員中的一個,就可以匹配成功,並且將括號中的成員也作爲匹配到的內容,如下案例,匹配到的內容就是至尊大寶、至尊玉、至尊小寶:
String regex = "至尊(?:大寶|玉|小寶)";
String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
if(matcher.find()){
String group = matcher.group();
System.out.println(group);
}
//(?=)向後匹配,預測語句其後包含括號中內容,但不捕獲
//語法解析,至尊後面只要有大寶、玉、小寶三個成員中的一個,就會匹配成功,但是匹配結果並不會包含這三個成員,也就是說,該語句的匹配到的內容是:至尊、至尊、至尊
String regex = "至尊(?=大寶|玉|小寶)";
String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
Pattern pattern = Pattern.compile(regex);
Matchermatcher = pattern.matcher(text);
if(matcher.find()){
String group = matcher.group();
System.out.println(group);
}
//(?!)向後匹配,預測語句之後不包含括號內容,但不捕獲
//語法解析:至尊後面只要不包含大寶、玉、小寶的字樣,就可以匹配成功,如下案例匹配到的內容是:至尊寶,但是括號中的不包含的內容“寶”字也不會被捕獲,即他的功能只是預測一下至尊後面是不是不包含某些字眼,並不會將該字眼之外的內容捕獲放到匹配到的內容當中,所以如下結果打印爲:至尊
String regex = "至尊(?!大寶|玉|小寶)";
String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
if(matcher.find()){
Stringgroup = matcher.group();
System.out.println(group);
}