Java基础:正则表达式
相關(guān)閱讀
1. 正則表達(dá)式概述
正則表達(dá)式,又稱正規(guī)表示法、常規(guī)表示法(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),計(jì)算機(jī)科學(xué)的一個(gè)概念。正則表達(dá)式使用單個(gè)字符串來描述、匹配一系列符合某個(gè)句法規(guī)則的字符串。在很多文本編輯器里,正則表達(dá)式通常被用來檢索、替換那些符合某個(gè)模式的文本
許多程序設(shè)計(jì)語言都支持利用正則表達(dá)式進(jìn)行字符串操作。例如,在Perl中就內(nèi)建了一個(gè)功能強(qiáng)大的正則表達(dá)式引擎。正則表達(dá)式這個(gè)概念最初是由Unix中的工具軟件(例如sed和grep)普及開的。正則表達(dá)式通常縮寫成“regex”,單數(shù)有regexp、regex,復(fù)數(shù)有regexps、regexes、regexen
正則表達(dá)式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對字符串的一種過濾邏輯
1.1 給定一個(gè)正則表達(dá)式和另一個(gè)字符串,我們可以達(dá)到如下的目的
- 給定的字符串是否符合正則表達(dá)式的過濾邏輯(稱作“匹配”)
- 可以通過正則表達(dá)式,從字符串中獲取我們想要的特定部分
1.2 正則表達(dá)式的特點(diǎn)
- 靈活性、邏輯性和功能性非常的強(qiáng);
- 可以迅速地用極簡單的方式達(dá)到字符串的復(fù)雜控制。
- 對于剛接觸的人來說,比較晦澀難懂。
由于正則表達(dá)式主要應(yīng)用對象是文本,因此它在各種文本編輯器場合都有應(yīng)用,小到著名編輯器EditPlus,大到Microsoft Word、Visual Studio等大型編輯器,都可以使用正則表達(dá)式來處理文本內(nèi)容
2. 正則表達(dá)式基礎(chǔ)知識
2.1 規(guī)則字符在java.util.regex Pattern類中
2.2 常見符號
2.2.1 字符
| X | 字符X |
| \\ | 反斜線 |
| \t | 制表符 (‘\u0009’) |
| \n | 回車 |
| \r | 換行 |
| \f | 換頁符 (‘\u000C’) |
| \a | 報(bào)警 (bell) 符 (‘\u0007’) |
2.2.2 字符類
| [abc] | a、b或c |
| [^abc] | 任何字符,除了a、b或c |
| [a-zA-Z] | a到z,或A到Z |
| [0-9] | 0到9的字符 |
| [a-d[m-p]] | a到 d或 m 到 p:[a-dm-p](并集) |
| [a-z&&[def]] | d、e或 f(交集) |
| [a-z&&[^bc]] | a到 z,除了 b和 c:[ad-z](減去) |
| [a-z&&[^m-p]] | a到 z,而非 m到 p:[a-lq-z](減去) |
2.2.3 預(yù)定義字符
| . | 任何字符 |
| \d | 數(shù)字:[0-9] |
| \D | 非數(shù)字: [^0-9] |
| \s | 空白字符:[ \t\n\x0B\f\r] |
| \S | 非空白字符:[^\s] |
| \w | 單詞字符:[a-zA-Z_0-9] |
| \W | 非單詞字符:[^\w] |
2.3 邊界匹配器
| ^ | 行開頭 |
| $ | 行結(jié)尾 |
| \b | 單詞邊界 |
| \B | 非單詞邊界 |
| \A | 輸入的開頭 |
| \G | 上一個(gè)匹配的結(jié)尾 |
| \Z | 輸入的結(jié)尾,僅用于最后的結(jié)束符(如果有的話) |
| \z | 輸入的結(jié)尾 |
2.3.1 Greedy數(shù)量詞
| X? | 0次或1次 |
| X* | 0次以上 |
| X+ | 1次以上 |
| X{n} | 恰好n次 |
| X{n,} | 至少n次 |
| X{n,m} | n-m次 |
2.3.2 組和捕獲
分組可以分為兩種形式,捕獲組和非捕獲組。
捕獲組可以通過從左到右計(jì)算其開括號來編號。例如,在表達(dá)式 ((A)(B(C)))中,存在四個(gè)這樣的組:
- 分組0:((A)(B(C)))
- 分組1:(A)
- 分組2:(B(C))
- 分組3:(C)
正則表達(dá)式中每個(gè)”()”內(nèi)的部分算作一個(gè)捕獲組,每個(gè)捕獲組都有一個(gè)編號,從1,2…,編號0代表整個(gè)匹配到的內(nèi)容,組零始終代表整個(gè)表達(dá)式。
之所以這樣命名捕獲組是因?yàn)樵谄ヅ渲?#xff0c;保存了與這些組匹配的輸入序列的每個(gè)子序列。捕獲的子序列稍后可以通過 Back 引用(反向引用) 在表達(dá)式中使用,也可以在匹配操作完成后從匹配器檢索。
Back引用(\n)是說在后面的表達(dá)式中我們可以使用組的編號來引用前面的表達(dá)式所捕獲到的文本序列。注意:反向引用,引用的是前面捕獲組中的文本而不是正則,也就是說反向引用處匹配的文本應(yīng)和前面捕獲組中的文本相同,這一點(diǎn)很重要。
例如 ([” ‘]).*\1 其中使用了分組,\1就是對引號這個(gè)分組的引用,它匹配包含在兩個(gè)引號或者兩個(gè)單引號中的所有字符串,如,”abc” 或 “’ ” 或’ ” ’ ,但是請注意,它并不會對”a’或者 ‘a(chǎn)”匹配。原因上面已經(jīng)說明,Back引用只是引用文本而不是表達(dá)式。
捕獲組的作用就是為了可以在正則表達(dá)式內(nèi)部或者外部(Java方法)引用它。在另一個(gè)字符串引用捕獲組的內(nèi)容的方法(“"),在替換中常用匹配組的內(nèi)容。$n用來匹配第n個(gè)()里的內(nèi)容。
利用Matcher中的group(int group)獲取捕獲組內(nèi)容。
- 捕獲組命名
如果捕獲組的數(shù)量非常多,那都用數(shù)字進(jìn)行編號并引用將會非常混亂,并且難以記憶每個(gè)捕獲組的內(nèi)容及意義,因此對捕獲組命名顯得尤為重要;Java 7開始提供了對捕獲組命名的語法,并且可以通過捕獲組的名稱對捕獲組反向引用(內(nèi)外都行)。
命名捕獲組的語法格式:(?<自定義名>expr),例如:(?\d{4})-(?\d{2}-(?\d{2}))
有三個(gè)命名捕獲組year、date和day,從左到右編號分別為1、2、3(編號同樣是有效的)
- 非捕獲組
非捕獲組,只需要將捕獲組中”()”變?yōu)椤??:)”即可。
以 (?) 開頭的組是純的非捕獲組,它不捕獲文本 ,也不針對組合計(jì)進(jìn)行計(jì)數(shù)。就是說,如果小括號中以?號開頭,那么這個(gè)分組就不會捕獲文本,當(dāng)然也不會有組的編號,因此也不存在Back引用。
我們通過捕獲組就能夠得到我們想要匹配的內(nèi)容了,那為什么還要有非捕獲組呢?原因是捕獲組捕獲的內(nèi)容是被存儲在內(nèi)存中,可供以后使用,比如反向引用就是引用的內(nèi)存中存儲的捕獲組中捕獲的內(nèi)容。而非捕獲組則不會捕獲文本,也不會將它匹配到的內(nèi)容單獨(dú)分組來放到內(nèi)存中。所以,使用非捕獲組較使用捕獲組更節(jié)省內(nèi)存。在實(shí)際情況中我們要酌情選用。
3. 正則表達(dá)式的應(yīng)用
3.1 判斷功能
public boolean matches(String regex):編譯給定正則表達(dá)式并嘗試將給定輸入與其匹配。3.2 分割功能
public String[] split(String regex):根據(jù)指定的正則表達(dá)式分割字符串3.3 替換功能
public String replaceAll(String regex,String replacement)使用給定的 replacement 替換此字符串所有匹配給定的正則表達(dá)式的子字符串。
3.4 獲取功能
Pattern和Matcher類的使用
package cn.itcast_05; import java.util.regex.Matcher; import java.util.regex.Pattern; /** 獲取功能* Pattern和Matcher類的使用* * 模式和匹配器的基本使用順序*/ public class RegexDemo {public static void main(String[] args) {// 模式和匹配器的典型調(diào)用順序// 把正則表達(dá)式編譯成模式對象Pattern p = Pattern.compile("a*b");// 通過模式對象得到匹配器對象,這個(gè)時(shí)候需要的是被匹配的字符串Matcher m = p.matcher("aaaaab");// 調(diào)用匹配器對象的功能boolean b = m.matches();System.out.println(b);//這個(gè)是判斷功能,但是如果做判斷,這樣做就有點(diǎn)麻煩了,我們直接用字符串的方法做String s = "aaaaab";String regex = "a*b";boolean bb = s.matches(regex);System.out.println(bb);} }Pattern 匹配模式
| compile() | 把正則表達(dá)式編譯成匹配模式 |
| matcher() | 根據(jù)匹配模式去匹配指定的字符串,得到匹配器 |
Matcher 匹配器
| matches() | 匹配字符串 |
| find() | 查找有沒有滿足條件的子串 |
| group() | 獲取滿足條件的子串 |
3.4 注意事項(xiàng)
Pattern類為正則表達(dá)式的編譯表示形式。指定為字符串的正則表達(dá)式必須首先被編譯為此類的實(shí)例。然后,可將得到的模式用于創(chuàng)建Matcher對象,依照正則表達(dá)式,該對象可以與任意字符序列匹配。執(zhí)行匹配所涉及的所有狀態(tài)都駐留在匹配器中,所以多個(gè)匹配器可以共享同一模式
4. 正則表達(dá)式的練習(xí)
4.1 判斷功能:校驗(yàn)郵箱
package cn.itcast_02; import java.util.Scanner; /** 校驗(yàn)郵箱* * 分析:* A:鍵盤錄入郵箱* B:定義郵箱的規(guī)則* 1517806580@qq.com* liuyi@163.com* linqingxia@126.com* fengqingyang@sina.com.cn* fqy@itcast.cn* C:調(diào)用功能,判斷即可* D:輸出結(jié)果*/ public class RegexTest {public static void main(String[] args) {//鍵盤錄入郵箱Scanner sc = new Scanner(System.in);System.out.println("請輸入郵箱:");String email = sc.nextLine();//定義郵箱的規(guī)則//String regex = "[a-zA-Z_0-9]+@[a-zA-Z_0-9]{2,6}(\\.[a-zA-Z_0-9]{2,3})+";String regex = "\\w+@\\w{2,6}(\\.\\w{2,3})+";//調(diào)用功能,判斷即可boolean flag = email.matches(regex);//輸出結(jié)果System.out.println("flag:"+flag);} }4.2 分割功能
代碼示例:我有如下一個(gè)字符串:”91 27 46 3850”,請寫代碼實(shí)現(xiàn)最終輸出結(jié)果是:”27 3846 50 91”
package cn.itcast_03; import java.util.Arrays; /** 我有如下一個(gè)字符串:"91 27 46 38 50"* 請寫代碼實(shí)現(xiàn)最終輸出結(jié)果是:"27 38 46 50 91"* * 分析:* A:定義一個(gè)字符串* B:把字符串進(jìn)行分割,得到一個(gè)字符串?dāng)?shù)組* C:把字符串?dāng)?shù)組變換成int數(shù)組* D:對int數(shù)組排序* E:把排序后的int數(shù)組在組裝成一個(gè)字符串* F:輸出字符串*/ public class RegexTest {public static void main(String[] args) {// 定義一個(gè)字符串String s = "91 27 46 38 50";// 把字符串進(jìn)行分割,得到一個(gè)字符串?dāng)?shù)組String[] strArray = s.split(" ");// 把字符串?dāng)?shù)組變換成int數(shù)組int[] arr = new int[strArray.length];for (int x = 0; x < arr.length; x++) {arr[x] = Integer.parseInt(strArray[x]);}// 對int數(shù)組排序Arrays.sort(arr);// 把排序后的int數(shù)組在組裝成一個(gè)字符串StringBuilder sb = new StringBuilder();for (int x = 0; x < arr.length; x++) {sb.append(arr[x]).append(" ");}//轉(zhuǎn)化為字符串String result = sb.toString().trim();//輸出字符串System.out.println("result:"+result);} }4.3 替換功能:論壇中不能出現(xiàn)數(shù)字字符,用*替換
package cn.itcast_04; /** 替換功能* String類的public String replaceAll(String regex,String replacement)* 使用給定的 replacement 替換此字符串所有匹配給定的正則表達(dá)式的子字符串。 */ public class RegexDemo {public static void main(String[] args) {// 定義一個(gè)字符串String s = "helloqq12345worldkh622112345678java";// 我要去除所有的數(shù)字,用*給替換掉// String regex = "\\d+";// String regex = "\\d";//String ss = "*";// 直接把數(shù)字干掉String regex = "\\d+";String ss = "";String result = s.replaceAll(regex, ss);System.out.println(result);} }4.4 獲取功能:獲取由三個(gè)字符組成的單詞
package cn.itcast_05; import java.util.regex.Matcher; import java.util.regex.Pattern; /** 獲取功能:* 獲取下面這個(gè)字符串中由三個(gè)字符組成的單詞* da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?*/ public class RegexDemo2 {public static void main(String[] args) {// 定義字符串String s = "da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?";// 規(guī)則String regex = "\\b\\w{3}\\b";// 把規(guī)則編譯成模式對象Pattern p = Pattern.compile(regex);// 通過模式對象得到匹配器對象Matcher m = p.matcher(s);// 調(diào)用匹配器對象的功能// 通過find方法就是查找有沒有滿足條件的子串// public boolean find()// boolean flag = m.find();// System.out.println(flag);// // 如何得到值呢?// // public String group()// String ss = m.group();// System.out.println(ss);//// // 再來一次// flag = m.find();// System.out.println(flag);// ss = m.group();// System.out.println(ss);while (m.find()) {System.out.println(m.group());}// 注意:一定要先find(),然后才能group()// IllegalStateException: No match found// String ss = m.group();// System.out.println(ss);} }5. 正則表達(dá)式工具類
import java.util.regex.Matcher; import java.util.regex.Pattern;/*** 正則工具類 提供驗(yàn)證郵箱、手機(jī)號、電話號碼、身份證號碼、數(shù)字等方法*/ public final class RegexUtils {/*** 驗(yàn)證Email* * @param email* email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,xxx代表郵件服務(wù)商* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false ^ :匹配輸入的開始位置。 \:將下一個(gè)字符標(biāo)記為特殊字符或字面值。* :匹配前一個(gè)字符零次或幾次。 + :匹配前一個(gè)字符一次或多次。 (pattern) 與模式匹配并記住匹配。 x|y:匹配 x 或* y。 [a-z] :表示某個(gè)范圍內(nèi)的字符。與指定區(qū)間內(nèi)的任何字符匹配。 \w :與任何單詞字符匹配,包括下劃線。* * {n,m} 最少匹配 n 次且最多匹配 m 次 $ :匹配輸入的結(jié)尾。*/public static boolean checkEmail(String email) {String regex = "^(\\w)+(\\.\\w+)*@(\\w)+((\\.\\w{2,3}){1,3})$";return Pattern.matches(regex, email);}/*** 驗(yàn)證身份證號碼* * @param idCard* 居民身份證號碼15位或18位,最后一位可能是數(shù)字或字母* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkIdCard(String idCard) {String regex = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}";return Pattern.matches(regex, idCard);}/*** 驗(yàn)證手機(jī)號碼(支持國際格式,+86135xxxx...(中國內(nèi)地),+00852137xxxx...(中國香港))* * @param mobile* 移動(dòng)、聯(lián)通、電信運(yùn)營商的號碼段* <p>* 移動(dòng)的號段:134(0-8)、135、136、137、138、139、147(預(yù)計(jì)用于TD上網(wǎng)卡)* 、150、151、152、157(TD專用)、158、159、187(未啟用)、188(TD專用)* </p>* <p>* 聯(lián)通的號段:130、131、132、155、156(世界風(fēng)專用)、185(未啟用)、186(3g)* </p>* <p>* 電信的號段:133、153、180(未啟用)、189* </p>* <p>* 虛擬運(yùn)營商的號段:170* </p>* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkMobile(String mobile) {String regex = "(\\+\\d+)?1[34578]\\d{9}$";return Pattern.matches(regex, mobile);}/*** 驗(yàn)證固定電話號碼* * @param phone* 電話號碼,格式:國家(地區(qū))電話代碼 + 區(qū)號(城市代碼) + 電話號碼,如:+8602085588447* <p>* <b>國家(地區(qū)) 代碼 :</b>標(biāo)識電話號碼的國家(地區(qū))的標(biāo)準(zhǔn)國家(地區(qū))代碼。它包含從 0 到 9* 的一位或多位數(shù)字, 數(shù)字之后是空格分隔的國家(地區(qū))代碼。* </p>* <p>* <b>區(qū)號(城市代碼):</b>這可能包含一個(gè)或多個(gè)從 0 到 9 的數(shù)字,地區(qū)或城市代碼放在圓括號——* 對不使用地區(qū)或城市代碼的國家(地區(qū)),則省略該組件。* </p>* <p>* <b>電話號碼:</b>這包含從 0 到 9 的一個(gè)或多個(gè)數(shù)字* </p>* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkPhone(String phone) {// String regex = "(\\+\\d+)?(\\d{3,4}\\-?)?\\d{7,8}$";String regex = "^1\\d{10}$";return Pattern.matches(regex, phone);}/*** 驗(yàn)證整數(shù)(正整數(shù)和負(fù)整數(shù))* * @param digit* 一位或多位0-9之間的整數(shù)* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkDigit(String digit) {String regex = "\\-?[1-9]\\d+";return Pattern.matches(regex, digit);}/*** 驗(yàn)證整數(shù)和浮點(diǎn)數(shù)(正負(fù)整數(shù)和正負(fù)浮點(diǎn)數(shù))* * @param decimals* 一位或多位0-9之間的浮點(diǎn)數(shù),如:1.23,233.30* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkDecimals(String decimals) {String regex = "\\-?[1-9]\\d+(\\.\\d+)?";return Pattern.matches(regex, decimals);}/*** 驗(yàn)證空白字符* * @param blankSpace* 空白字符,包括:空格、\t、\n、\r、\f、\x0B* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkBlankSpace(String blankSpace) {String regex = "\\s+";return Pattern.matches(regex, blankSpace);}/*** 驗(yàn)證中文* * @param chinese* 中文字符* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkChinese(String chinese) {String regex = "^[\u4E00-\u9FA5]+$";return Pattern.matches(regex, chinese);}/*** 驗(yàn)證日期(年月日)* * @param birthday* 日期,格式:1992-09-03,或1992.09.03* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkBirthday(String birthday) {String regex = "[1-9]{4}([-./])\\d{1,2}\\1\\d{1,2}";return Pattern.matches(regex, birthday);}/*** 驗(yàn)證URL地址* * @param url* 格式:http://blog.csdn.net:80/xyang81/article/details/7705960? 或* http://www.csdn.net:80* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkURL(String url) {String regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?";return Pattern.matches(regex, url);}/*** 匹配中國郵政編碼* * @param postcode* 郵政編碼* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkPostcode(String postcode) {String regex = "[1-9]\\d{5}";return Pattern.matches(regex, postcode);}/*** 匹配IP地址(簡單匹配,格式,如:192.168.1.1,127.0.0.1,沒有匹配IP段的大小)* * @param ipAddress* IPv4標(biāo)準(zhǔn)地址* @return 驗(yàn)證成功返回true,驗(yàn)證失敗返回false*/public static boolean checkIpAddress(String ipAddress) {String regex = "[1-9](\\d{1,2})?\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))";return Pattern.matches(regex, ipAddress);}public static boolean checkNickname(String nickname) {String regex = "^[a-zA-Z0-9\u4E00-\u9FA5_]+$";return Pattern.matches(regex, nickname);}public static boolean hasCrossSciptRiskInAddress(String str) {String regx = "[`~!@#$%^&*+=|{}':;',\\[\\].<>~!@#¥%……&*——+|{}【】‘;:”“’。,、?-]";if (str != null) {str = str.trim();Pattern p = Pattern.compile(regx, Pattern.CASE_INSENSITIVE);Matcher m = p.matcher(str);return m.find();}return false;} }總結(jié)
以上是生活随笔為你收集整理的Java基础:正则表达式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java字符串格式化
- 下一篇: Android Manager