Java正則表達(dá)式——group方法的使用
Java正則表達(dá)式——group方法
捕獲組是把多個(gè)字符當(dāng)一個(gè)單獨(dú)單元進(jìn)行處理的方法,它通過對(duì)括號(hào)內(nèi)的字符分組來創(chuàng)建。
例如,正則表達(dá)式 (dog) 創(chuàng)建了單一分組,組里包含"d","o",和"g"。
捕獲組是通過從左至右計(jì)算其開括號(hào)來編號(hào)。例如,在表達(dá)式((A)(B(C))),有四個(gè)這樣的組:
- ((A)(B(C)))
- (A)
- (B(C))
- (C)
可以通過調(diào)用 matcher 對(duì)象的 groupCount 方法來查看表達(dá)式有多少個(gè)分組。groupCount 方法返回一個(gè) int 值,表示matcher對(duì)象當(dāng)前有多個(gè)捕獲組。
在Java正則表達(dá)式的相關(guān)類Matcher中,有如下幾個(gè)方法:
- int groupCount()? - String group(int group)? - int start(int group)? - int end(int group)? - String group(String name)? - int start(String name)? - int end(String name)
例子Demo1
String text = "John writes about this, and John Doe writes about that," ? ? ? ? ? ? ? ? + " and John Wayne writes about everything."; String patternString = "(John) (.+?) "; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(text); matcher.find();//匹配字符串,匹配到的字符串可以在任何位置 int start = matcher.start();//返回當(dāng)前匹配到的字符串在原目標(biāo)字符串中的位置 int end = matcher.end();//返回當(dāng)前匹配的字符串的最后一個(gè)字符在原目標(biāo)字符串中的索引位置 System.out.println("found group: group(0) is '" + matcher.group(0)); System.out.println("found group: group(1) is '" + matcher.group(1) + "',group(2) is '" + matcher.group(2)+"'"); ? patternString= "(?:John)"; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(text); System.out.println("groupCount is -->" + matcher.groupCount()); while (matcher.find()) { ? ? System.out.println("found: " + matcher.group(1)); }
運(yùn)行結(jié)果:
found group: group(0) is ‘John writes
found group: group(1) is ‘John’,group(2) is ‘writes’
groupCount is –>0
Exception in thread “main” java.lang.IndexOutOfBoundsException: No group 1
從輸出結(jié)果可以看出,當(dāng)正則表達(dá)式包含多個(gè)group時(shí),也就是含有多個(gè)’(pattern)’格式的子表達(dá)式時(shí),它的分組索引(group number)是從1開始的,而group(0)代表了整個(gè)匹配的字符串.
總結(jié):
(1)正則表達(dá)式中以'()'標(biāo)記的子表達(dá)式所匹配的內(nèi)容就是一個(gè)分組(group),分組索引是從1開始的,0代表正則表達(dá)式匹配的整個(gè)字符串,group(i)代表第i組匹配的內(nèi)容。
(2)groupCount() 函數(shù)返回當(dāng)前正則表達(dá)式中分組的個(gè)數(shù)。
(3)類似于(?:pattern)格式的子表達(dá)式不能算是一個(gè)分組。
例子Demo2
String text = "John writes about this, and John Doe writes about that," ? ? ? ? ? ? ? ? + " and John Wayne writes about everything."; String patternString = "(John) (.+?) "; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(text); matcher.find();//匹配字符串,匹配到的字符串可以在任何位置 int start = matcher.start();//返回當(dāng)前匹配到的字符串在原目標(biāo)字符串中的位置 System.out.println(start);//0 int end = matcher.end();//返回當(dāng)前匹配的字符串的最后一個(gè)字符在原目標(biāo)字符串中的索引位置 System.out.println(end);//12 start = matcher.start(1);//第一個(gè)分組匹配的內(nèi)容,也就是John開始的索引位置,0 System.out.println(start);//0 start = matcher.start(2);//第一個(gè)分組匹配的內(nèi)容,也就是writes開始的索引位置,5 System.out.println(start);//5 end = matcher.end(1);//第一個(gè)分組匹配的內(nèi)容,也就是John結(jié)束的索引位置,4 System.out.println(end);//4 end = matcher.end(2);//第二個(gè)分組匹配的內(nèi)容,也就是writes開始的索引位置,12 System.out.println(end);//12 start = matcher.start(3);//Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 3
總結(jié):
(1)當(dāng)索引大于正則表達(dá)式中實(shí)際存在的索引數(shù)量,也就是groupCount()返回值時(shí)會(huì)拋出異常。
(2)int start(int group) 返回當(dāng)前分組匹配到的字符串在原目標(biāo)字符串中的位置。
(3)返回當(dāng)前分組匹配的字符串的最后一個(gè)字符在原目標(biāo)字符串中的索引位置。
Java正則表達(dá)式校驗(yàn)實(shí)例
1 通過正則表達(dá)式制作短信模板
1.1 java 替換 ${xxx} 的內(nèi)容
private static String parse(String content,Map<String,String> kvs){ Matcher m = p.matcher(content); StringBuffer sr = new StringBuffer(); while(m.find()){ String group = m.group(); m.appendReplacement(sr, kvs.get(group)); } m.appendTail(sr); return sr.toString(); } public static void main(String[] args) { Map<String,String> m=new HashMap<>(); m.put("${a}","han"); m.put("$","zhong"); System.out.println( parse("例如有這樣一個(gè)${a}字符串字符串:用戶'${a}'的名稱$", m)); }
1.2 java正則表達(dá)式appendReplacement和appendTail方法
appendReplacement是java中替換相應(yīng)字符串的一個(gè)方法
appendReplacement(StringBuffer sb,String replacement)
將當(dāng)前匹配子串替換為指定字符串,并且將替換后的子串以及其之前到上次匹配子串之后的字符串段添加到一個(gè) StringBuffer 對(duì)象里
appendTail(StringBuffer sb)
將最后一次匹配工作后剩余的字符串添加到一個(gè) StringBuffer 對(duì)象里
如果沒有理解的話,那就來一個(gè)簡(jiǎn)單的demo吧
public class TheReplacements { public static void main(String[] args) throws Exception { // 生成 Pattern 對(duì)象并且編譯一個(gè)簡(jiǎn)單的正則表達(dá)式"cat" Pattern p = Pattern.compile("cat"); // 用 Pattern 類的 matcher() 方法生成一個(gè) Matcher 對(duì)象 Matcher m = p.matcher("fatcatfatcatfat"); StringBuffer sb = new StringBuffer(); while(m.find()){ //此時(shí)sb為fatdogfatdog,cat被替換為dog,并且將最后匹配到之前的子串都添加到sb對(duì)象中 m.appendReplacement(sb,"dog"); } //此時(shí)sb為fatdogfatdogfat,將最后匹配到后面的子串添加到sb對(duì)象中 m.appendTail(sb); //輸出內(nèi)容為fatdogfatdogfat System.out.println("sb:"+sb); } }
1.3 正則表達(dá)式matcher.group()用法
package cn.oldlu.regexp.singlecharacter; import java.util.regex.Matcher; import java.util.regex.Pattern; public class GroupIndexAndStartEndIndexTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String str = "Hello,World! in Java."; Pattern pattern = Pattern.compile("W(or)(ld!)"); Matcher matcher = pattern.matcher(str); while(matcher.find()){ System.out.println("Group 0:"+matcher.group(0));//得到第0組——整個(gè)匹配 System.out.println("Group 1:"+matcher.group(1));//得到第一組匹配——與(or)匹配的 System.out.println("Group 2:"+matcher.group(2));//得到第二組匹配——與(ld!)匹配的,組也就是子表達(dá)式 System.out.println("Start 0:"+matcher.start(0)+" End 0:"+matcher.end(0));//總匹配的索引 System.out.println("Start 1:"+matcher.start(1)+" End 1:"+matcher.end(1));//第一組匹配的索引 System.out.println("Start 2:"+matcher.start(2)+" End 2:"+matcher.end(2));//第二組匹配的索引 System.out.println(str.substring(matcher.start(0),matcher.end(1)));//從總匹配開始索引到第1組匹配的結(jié)束索引之間子串——Wor } } }
運(yùn)行結(jié)果:
Group 0:World!
Group 1:or
Group 2:ld!
Start 0:6 End 0:12
Start 1:7 End 1:9
Start 2:9 End 2:12
Wor
2 正則表達(dá)式校驗(yàn)身份證
身份證號(hào)碼驗(yàn)證
1、號(hào)碼的結(jié)構(gòu) 公民身份號(hào)碼是特征組合碼,由十七位數(shù)字本體碼和一位校驗(yàn)碼組成。排列順序從左至右依次為:六位數(shù)字地址碼,八位數(shù)字出生日期碼,三位數(shù)字順序碼和一位數(shù)字校驗(yàn)碼
2、地址碼(前六位數(shù))表示編碼對(duì)象常住戶口所在縣(市、旗、區(qū))的行政區(qū)劃代碼,按GB/T2260的規(guī)定執(zhí)行
3、出生日期碼(第七位至十四位)表示編碼對(duì)象出生的年、月、日,按GB/T7408的規(guī)定執(zhí)行,年、月、日代碼之間不用分隔符
4、順序碼(第十五位至十七位)表示在同一地址碼所標(biāo)識(shí)的區(qū)域范圍內(nèi),對(duì)同年、同月、同日出生的人編定的順序號(hào), 順序碼的奇數(shù)分配給男性,偶數(shù)分配給女性
5、校驗(yàn)碼(第十八位數(shù))
(1)十七位數(shù)字本體碼加權(quán)求和公式 S = Sum(iDCardNo * wf), i = 0, … , 16 ,先對(duì)前17位數(shù)字的權(quán)求和 iDCardNo:表示第i位置上的身份證號(hào)碼數(shù)字值 Wi:表示第i位置上的加權(quán)因子 wf: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
(2)計(jì)算模 Y = mod(S, 11) (3)通過模得到對(duì)應(yīng)的校驗(yàn)碼 Y: 0 1 2 3 4 5 6 7 8 9 10 校驗(yàn)碼: 1 0 X 9 8 7 6 5 4 3 2
import org.junit.Test; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Hashtable; import java.util.regex.Matcher; import java.util.regex.Pattern; public class JunitIDCardTest { @Test public void test(){ System.out.println(IdentityCardVerification("110101199003074370")); } /** *身份證驗(yàn)證 * @param idStr * @return */ public static String IdentityCardVerification(String idStr){ String[] wf = { "1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2" }; String[] checkCode = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2" }; String iDCardNo = ""; try { //判斷號(hào)碼的長(zhǎng)度 15位或18位 if (idStr.length() != 15 && idStr.length() != 18) { return "身份證號(hào)碼長(zhǎng)度應(yīng)該為15位或18位"; } if (idStr.length() == 18) { iDCardNo = idStr.substring(0, 17); } else if (idStr.length() == 15) { iDCardNo = idStr.substring(0, 6) + "19" + idStr.substring(6, 15); } if (isStrNum(iDCardNo) == false) { return "身份證15位號(hào)碼都應(yīng)為數(shù)字;18位號(hào)碼除最后一位外,都應(yīng)為數(shù)字"; } //判斷出生年月 String strYear = iDCardNo.substring(6, 10);// 年份 String strMonth = iDCardNo.substring(10, 12);// 月份 String strDay = iDCardNo.substring(12, 14);// 月份 if (isStrDate(strYear + "-" + strMonth + "-" + strDay) == false) { return "身份證生日無效"; } GregorianCalendar gc = new GregorianCalendar(); SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd"); if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150 || (gc.getTime().getTime() - s.parse(strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) { return "身份證生日不在有效范圍"; } if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) { return "身份證月份無效"; } if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) { return "身份證日期無效"; } //判斷地區(qū)碼 Hashtable h = GetAreaCode(); if (h.get(iDCardNo.substring(0, 2)) == null) { return "身份證地區(qū)編碼錯(cuò)誤"; } //判斷最后一位 int theLastOne = 0; for (int i = 0; i < 17; i++) { theLastOne = theLastOne + Integer.parseInt(String.valueOf(iDCardNo.charAt(i))) * Integer.parseInt(checkCode[i]); } int modValue = theLastOne % 11; String strVerifyCode = wf[modValue]; iDCardNo = iDCardNo + strVerifyCode; if (idStr.length() == 18 &&!iDCardNo.equals(idStr)) { return "身份證無效,不是合法的身份證號(hào)碼"; } }catch (Exception e){ e.printStackTrace(); } return ""; } /** * 地區(qū)代碼 * @return Hashtable */ private static Hashtable GetAreaCode() { Hashtable hashtable = new Hashtable(); hashtable.put("11", "北京"); hashtable.put("12", "天津"); hashtable.put("13", "河北"); hashtable.put("14", "山西"); hashtable.put("15", "內(nèi)蒙古"); hashtable.put("21", "遼寧"); hashtable.put("22", "吉林"); hashtable.put("23", "黑龍江"); hashtable.put("31", "上海"); hashtable.put("32", "江蘇"); hashtable.put("33", "浙江"); hashtable.put("34", "安徽"); hashtable.put("35", "福建"); hashtable.put("36", "江西"); hashtable.put("37", "山東"); hashtable.put("41", "河南"); hashtable.put("42", "湖北"); hashtable.put("43", "湖南"); hashtable.put("44", "廣東"); hashtable.put("45", "廣西"); hashtable.put("46", "海南"); hashtable.put("50", "重慶"); hashtable.put("51", "四川"); hashtable.put("52", "貴州"); hashtable.put("53", "云南"); hashtable.put("54", "西藏"); hashtable.put("61", "陜西"); hashtable.put("62", "甘肅"); hashtable.put("63", "青海"); hashtable.put("64", "寧夏"); hashtable.put("65", "新疆"); hashtable.put("71", "臺(tái)灣"); hashtable.put("81", "香港"); hashtable.put("82", "澳門"); hashtable.put("91", "國(guó)外"); return hashtable; } /** * 判斷字符串是否為數(shù)字 * @param str * @return */ private static boolean isStrNum(String str) { Pattern pattern = Pattern.compile("[0-9]*"); Matcher isNum = pattern.matcher(str); if (isNum.matches()) { return true; } else { return false; } } /** * 判斷字符串是否為日期格式 * @param strDate * @return */ public static boolean isStrDate(String strDate) { Pattern pattern = Pattern.compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$"); Matcher m = pattern.matcher(strDate); if (m.matches()) { return true; } else { return false; } } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis-plus中wrapper的用法實(shí)例詳解
本文給大家介紹了mybatis-plus中wrapper的用法,包括條件構(gòu)造器關(guān)系、項(xiàng)目實(shí)例及具體使用操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02SpringBoot中實(shí)現(xiàn)異步調(diào)用@Async詳解
這篇文章主要介紹了SpringBoot中實(shí)現(xiàn)異步調(diào)用@Async詳解,在SpringBoot的日常開發(fā)中,一般都是同步調(diào)用的,但實(shí)際中有很多場(chǎng)景非常適合使用異步來處理,需要的朋友可以參考下2024-01-01Spring Boot2與Spring Boot3的區(qū)別小結(jié)
SpringBoot2和SpringBoot3之間有一些重要的區(qū)別,本文就來探討SpringBoot2和SpringBoot3之間的區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10解決SpringCloud Gateway配置自定義路由404的坑
這篇文章主要介紹了解決SpringCloud Gateway配置自定義路由404的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09十大常見Java String問題_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
本文介紹Java中關(guān)于String最常見的10個(gè)問題,需要的朋友參考下吧2017-04-04java中常見XML解析器的使用詳解(JAXP,DOM4J,Jsoup,JsoupXPath)
為了處理和操作XML數(shù)據(jù),我們需要使用XML解析器,本文將介紹幾種常用的XML解析器,包括JAXP、DOM4J、Jsoup和JsoupXPath,需要的小伙伴可以參考一下2023-11-11Spring Boot整合郵件發(fā)送與注意事項(xiàng)
這篇文章主要給大家介紹了關(guān)于Spring Boot整合郵件發(fā)送與注意事項(xiàng)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07