Java正則表達(dá)式——group方法的使用
Java正則表達(dá)式——group方法
捕獲組是把多個(gè)字符當(dāng)一個(gè)單獨(dú)單元進(jìn)行處理的方法,它通過(guò)對(duì)括號(hào)內(nèi)的字符分組來(lái)創(chuàng)建。
例如,正則表達(dá)式 (dog) 創(chuàng)建了單一分組,組里包含"d","o",和"g"。
捕獲組是通過(guò)從左至右計(jì)算其開(kāi)括號(hào)來(lái)編號(hào)。例如,在表達(dá)式((A)(B(C))),有四個(gè)這樣的組:
- ((A)(B(C)))
- (A)
- (B(C))
- (C)
可以通過(guò)調(diào)用 matcher 對(duì)象的 groupCount 方法來(lái)查看表達(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開(kāi)始的,而group(0)代表了整個(gè)匹配的字符串.
總結(jié):
(1)正則表達(dá)式中以'()'標(biāo)記的子表達(dá)式所匹配的內(nèi)容就是一個(gè)分組(group),分組索引是從1開(kāi)始的,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開(kāi)始的索引位置,0 System.out.println(start);//0 start = matcher.start(2);//第一個(gè)分組匹配的內(nèi)容,也就是writes開(kāi)始的索引位置,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開(kāi)始的索引位置,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 通過(guò)正則表達(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ì)象里
如果沒(méi)有理解的話,那就來(lái)一個(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)));//從總匹配開(kāi)始索引到第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)通過(guò)模得到對(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 "身份證生日無(wú)效";
}
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 "身份證月份無(wú)效";
}
if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) {
return "身份證日期無(wú)效";
}
//判斷地區(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 "身份證無(wú)效,不是合法的身份證號(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)文章
詳解SpringCloud Zuul過(guò)濾器返回值攔截
Zuul作為網(wǎng)關(guān)服務(wù),是其他各服務(wù)對(duì)外中轉(zhuǎn)站,通過(guò)Zuul進(jìn)行請(qǐng)求轉(zhuǎn)發(fā)。這篇文章主要介紹了詳解SpringCloud Zuul過(guò)濾器返回值攔截,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
springboot+HttpInvoke?實(shí)現(xiàn)RPC調(diào)用的方法
RPC框架大家或多或少都用過(guò),出自于阿里系的就有dubbo,HSF,sofaRPC等,今天通過(guò)本文給大家介紹springboot+HttpInvoke?實(shí)現(xiàn)RPC調(diào)用的方法,感興趣的朋友一起看看吧2022-03-03
SpringBoot使用讀寫鎖解決緩存一致性的問(wèn)題
本文主要介紹了SpringBoot使用讀寫鎖解決緩存一致性的問(wèn)題,通過(guò)在緩存類中維護(hù)一個(gè)讀寫鎖,可以在讀多寫少的場(chǎng)景下提高并發(fā)訪問(wèn)效率,感興趣的可以了解一下2025-03-03
@SpringBootConfiguration重復(fù)加載報(bào)錯(cuò)問(wèn)題解決
@SpringBootApplication?注解的?exclude?屬性用于排除特定的自動(dòng)配置類,而不是用于排除主配置類本身,因此,不能通過(guò)?exclude?屬性來(lái)排除主配置類的加載,這篇文章主要介紹了@SpringBootConfiguration重復(fù)加載報(bào)錯(cuò),需要的朋友可以參考下2024-08-08
SpringBoot實(shí)現(xiàn)過(guò)濾器攔截器的耗時(shí)對(duì)比
這篇文章主要為大家詳細(xì)介紹了SpringBoot實(shí)現(xiàn)過(guò)濾器攔截器的輸出接口耗時(shí)對(duì)比,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-06-06
基于@RestControllerAdvice與@ControllerAdvice的區(qū)別說(shuō)明
這篇文章主要介紹了@RestControllerAdvice與@ControllerAdvice的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09

