首頁 > 軟體

Java正規表示式——group方法的使用

2023-11-01 10:01:12

Java正規表示式——group方法

捕獲組是把多個字元當一個單獨單元進行處理的方法,它通過對括號內的字元分組來建立。

例如,正規表示式 (dog) 建立了單一分組,組裡包含"d","o",和"g"。

捕獲組是通過從左至右計算其開括號來編號。例如,在表示式((A)(B(C))),有四個這樣的組:

  • ((A)(B(C)))
  • (A)
  • (B(C))
  • (C)

可以通過呼叫 matcher 物件的 groupCount 方法來檢視表示式有多少個分組。groupCount 方法返回一個 int 值,表示matcher物件當前有多個捕獲組。

在Java正規表示式的相關類Matcher中,有如下幾個方法: 

- 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();//返回當前匹配到的字串在原目標字串中的位置
int end = matcher.end();//返回當前匹配的字串的最後一個字元在原目標字串中的索引位置
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));
}

執行結果:

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       

從輸出結果可以看出,當正規表示式包含多個group時,也就是含有多個’(pattern)’格式的子表示式時,它的分組索引(group number)是從1開始的,而group(0)代表了整個匹配的字串. 

總結:  

(1)正規表示式中以'()'標記的子表示式所匹配的內容就是一個分組(group),分組索引是從1開始的,0代表正規表示式匹配的整個字串,group(i)代表第i組匹配的內容。 

(2)groupCount() 函數返回當前正規表示式中分組的個數。

(3)類似於(?:pattern)格式的子表示式不能算是一個分組。

例子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();//返回當前匹配到的字串在原目標字串中的位置
System.out.println(start);//0
int end = matcher.end();//返回當前匹配的字串的最後一個字元在原目標字串中的索引位置
System.out.println(end);//12
start = matcher.start(1);//第一個分組匹配的內容,也就是John開始的索引位置,0
System.out.println(start);//0
start = matcher.start(2);//第一個分組匹配的內容,也就是writes開始的索引位置,5
System.out.println(start);//5
end = matcher.end(1);//第一個分組匹配的內容,也就是John結束的索引位置,4
System.out.println(end);//4
end = matcher.end(2);//第二個分組匹配的內容,也就是writes開始的索引位置,12
System.out.println(end);//12
start = matcher.start(3);//Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 3

總結:       

(1)當索引大於正規表示式中實際存在的索引數量,也就是groupCount()返回值時會丟擲異常。 

(2)int start(int group) 返回當前分組匹配到的字串在原目標字串中的位置。

(3)返回當前分組匹配的字串的最後一個字元在原目標字串中的索引位置。

Java正規表示式校驗範例

1 通過正規表示式製作簡訊模板

1.1 java 替換 ${xxx} 的內容

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("${b}","zhong");
        System.out.println( parse("例如有這樣一個${a}字串字串:使用者'${a}'的名稱${b}", m));
    }

1.2 java正規表示式appendReplacement和appendTail方法

appendReplacement是java中替換相應字串的一個方法

appendReplacement(StringBuffer sb,String replacement)

將當前匹配子串替換為指定字串,並且將替換後的子串以及其之前到上次匹配子串之後的字串段新增到一個 StringBuffer 物件裡

appendTail(StringBuffer sb)

將最後一次匹配工作後剩餘的字串新增到一個 StringBuffer 物件裡

如果沒有理解的話,那就來一個簡單的demo吧

public class TheReplacements {
    public static void main(String[] args) throws Exception {
        // 生成 Pattern 物件並且編譯一個簡單的正規表示式"cat"
        Pattern p = Pattern.compile("cat");
        // 用 Pattern 類的 matcher() 方法生成一個 Matcher 物件
        Matcher m = p.matcher("fatcatfatcatfat");
        StringBuffer sb = new StringBuffer();
        while(m.find()){
            //此時sb為fatdogfatdog,cat被替換為dog,並且將最後匹配到之前的子串都新增到sb物件中
            m.appendReplacement(sb,"dog");
        }
        //此時sb為fatdogfatdogfat,將最後匹配到後面的子串新增到sb物件中
        m.appendTail(sb);
        //輸出內容為fatdogfatdogfat
        System.out.println("sb:"+sb);
    }
}

1.3 正規表示式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組——整個匹配  
        System.out.println("Group 1:"+matcher.group(1));//得到第一組匹配——與(or)匹配的  
        System.out.println("Group 2:"+matcher.group(2));//得到第二組匹配——與(ld!)匹配的,組也就是子表示式  
        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組匹配的結束索引之間子串——Wor  
       }  
    }  
      
    }  

執行結果:

    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 正規表示式校驗身份證

身份證號碼驗證

1、號碼的結構 公民身份號碼是特徵組合碼,由十七位數位本體碼和一位校驗碼組成。排列順序從左至右依次為:六位數位地址碼,八位數位出生日期碼,三位數位順序碼和一位數位校驗碼

2、地址碼(前六位數)表示編碼物件常住戶口所在縣(市、旗、區)的行政區劃程式碼,按GB/T2260的規定執行

3、出生日期碼(第七位至十四位)表示編碼物件出生的年、月、日,按GB/T7408的規定執行,年、月、日程式碼之間不用分隔符

4、順序碼(第十五位至十七位)表示在同一地址碼所標識的區域範圍內,對同年、同月、同日出生的人編定的順序號, 順序碼的奇數分配給男性,偶數分配給女性

5、校驗碼(第十八位數)

(1)十七位數位本體碼加權求和公式 S = Sum(iDCardNo * wf), i = 0, … , 16 ,先對前17位數位的權求和 iDCardNo:表示第i位置上的身份證號碼數位值 Wi:表示第i位置上的加權因子 wf: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

(2)計算模 Y = mod(S, 11) (3)通過模得到對應的校驗碼 Y: 0 1 2 3 4 5 6 7 8 9 10 校驗碼: 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"));
    }

    /**
     *身份證驗證
     * @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 {
            //判斷號碼的長度 15位或18位元
            if (idStr.length() != 15 && idStr.length() != 18) {
                return "身份證號碼長度應該為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位號碼都應為數位;18位元號碼除最後一位外,都應為數位";
            }
            //判斷出生年月
            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 "身份證日期無效";
            }
            //判斷地區碼
            Hashtable h = GetAreaCode();
            if (h.get(iDCardNo.substring(0, 2)) == null) {
                return "身份證地區編碼錯誤";
            }
            //判斷最後一位
            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 "身份證無效,不是合法的身份證號碼";
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 地區程式碼
     * @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", "內蒙古");
        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", "臺灣");
        hashtable.put("81", "香港");
        hashtable.put("82", "澳門");
        hashtable.put("91", "國外");
        return hashtable;
    }
    /**
     * 判斷字串是否為數位
     * @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;
        }
    }
 }

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com