正則表達式(二)Java中正則表達式的使用


前言

在前面的《正則表達式(一)》的博文中已經記錄了正則表達式的基本語法,下面的內容主要是補充上一篇博文沒有介紹完全的一點內容以及記錄在Java語言中如何使用正則表達式進行字符串的判斷,提取信息和替換信息。

之所以使用Java語言,是因為JDK中已經內置好了正則表達式的庫,而且Java單元測試使用起來也非常方便,此外面向對象型的接口使用起來也更為舒適。

需要注意的是,在Java語言中,我們為了在字符串中表示反斜杠字符(\),我們需要輸入\\,因為在Java中\是一個用於轉義的字符,如\t\n等等,因此我們需要輸入兩個反斜杠來代表一個反斜杠字符了。例如表示匹配整數的表達式\d+,在Java中就需要寫成\\d+

一、非貪婪匹配

首先先看一個需求,我們的輸入是一串數字字符串,我們需要做的是它最后面的所有0字符和0前面的子串提取出來,例如:

  • "123000""123""000"
  • "110""11""0"
  • "1234""1234"""

我們很自然地可以寫出這樣的表達式:^(\d*)(0*)$

可是如果這樣寫匹配的結果和我們想象的是一樣嗎?

image-20210918000358088 image-20210918000510650

可以發現,分解的結果為:"123000""",與我們的想象完全不同。

產生這樣的結果的原因是:正則表達式默認使用貪婪匹配,任何一個規則,它總是盡可能多地向后匹配,因此,\d+總是會把后面的0包含進來。

而我們需要做的是使\d*盡量少匹配,而0*盡量多地匹配,這就需要使用到非貪婪匹配了,其含義即為使表達式盡量少地向后匹配。使用的方式是在某個量詞后面加上?,即原來的正則表達式需要修改為:^(\d*?)(0*)$,這樣我們的匹配結果為:

輸入串 結果
"123000" image-20210918001229183 image-20210918001256636
"110" image-20210918001414658 image-20210918001430408
"1234" image-20210918001506216 image-20210918001520476

可以發現現在得到的結果就是完全符合需求了。

二、Java中使用表達式判斷字符串

在Java中主要有三種使用方式:

法一(最常用)

使用String類中的成員方法boolean matches(String regex),使用方式如下所示:

@Test
public void t1() {
    String re = "^\\d+$";
    boolean isMatch = "123".matches(re);
    System.out.println(isMatch);
}

運行結果:

image-20210918002253873

其實點進去看String.matches的實現可以發現其內部也是使用正則表達式模塊的方法進行判斷的,即第二種方法。String.matches內部如下圖所示:

image-20210918002517193

法二

使用Pattern類的靜態方法boolean matches(String regex, CharSequence input),使用方式如下:

@Test
public void t2() {
   String re = "^\\d+$";
   boolean isMatch = Pattern.matches(re, "123");
   System.out.println(isMatch);
}

其實再觀察Pattern.matches的源碼可以發現它是使用PatternMatcher共同完成的:

// Pattern.matches源碼
public static boolean matches(String regex, CharSequence input) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(input);
    return m.matches();
}

因此我們還可以使用這種方式來進行匹配。

法三

使用PatternMatcher共同完成

和上面源碼的方式一樣,即:

@Test
public void t3() {
    String re = "^\\d+$";
    Pattern pattern = Pattern.compile(re);
    Matcher matcher = pattern.matcher("123");
    boolean isMatch = matcher.matches();
    System.out.println(isMatch);
}

工作流程是:

  1. 編譯表達式,得到一個模式對象(Pattern對象)
  2. 使用Pattern對象對輸入字符串進行匹配,得到匹配結果集Matcher對象,在Matcher對象中包括了全部的匹配信息,即包含所有匹配到的子串以及每個子串中的各個分組部分,例如:
    image-20210918001256636
  3. 使用Matcher對象提取需要的信息

后面會發現無論是提取信息還是替換信息都是按照這個流程來走的。

三、Java中使用表達式提取信息

提取信息就需要使用到前面使用到的分組查詢的符號()了,即需要提取的內容使用圓括號括起來,例如我們的需求還是上面那個將一個數字字符串的"0"串和前面的子串提取出來,我們的表達式和上面的一樣,為:^(\d*?)(0*)$

在Java中使用分組匹配也是按照上面判斷字符串是否匹配的【法三】一樣,需要分三步走,需要先后得到對應的Pattern對象和Matcher對象,然后我們需要使用到Matcher對象的成員方法String group(int group),即輸入分組索引,然后即可獲取到分組匹配到的內容,例如在可視化平台中我們使用這個表達式來匹配"123000",匹配的結果為:

image-20210918001229183 image-20210918001256636

可以看到group 1的結果為"123",group 2的結果為"000"

代碼示例如下:

@Test
public void t4() {
    String re = "^(\\d*?)(0*)$";
    Pattern pattern = Pattern.compile(re);       //1.創建Pattern對象
    Matcher matcher = pattern.matcher("123000"); //2.創建Matcher對象
    if (matcher.matches()) {                     //3.判斷是否匹配
        String front = matcher.group(1);         //4.使用group方法提取
        String end = matcher.group(2);
        System.out.printf("front: \"%s\", end: \"%s\"%n", front, end);
    }
}

運行結果:

image-20210918110114557

四、匹配多處信息

例如當前這樣的需求:給出一段輸入菜單字符串,提取出里面所有的金額數據並統計總價格。

例如輸入為:"咸魚茄子煲:20.5元,手撕包菜:13元,米飯:2元,紅燒肉:22.5元"

因此我們需要使用正則表達式匹配多處信息並將它們提取出來,我們需要匹配的是小數,寫出表達式為:(\d+(\.\d*)?)

輸入到可視化平台中的效果:

image-20210918110818120

可以發現,這個模式將所有的價格數字字符串都匹配到了,剩下的工作是我們如何匹配這多處信息並且將信息提取出來呢?

這個過程需要使用到Matcher對象的boolean find()成員方法,這個方法的作用是每次往下找到一個匹配的子串,如果找到了則返回true,否則返回false,因此我們可以使用這個方法不斷向下迭代直到匹配完所有的價格。提取信息的方法與【三】中介紹的還是一樣的。

代碼示例如下:

@Test
public void t5() {
    String re = "(\\d+(\\.\\d*)?)";
    Pattern pattern = Pattern.compile(re);
    Matcher matcher = pattern.matcher("咸魚茄子煲:20.5元,手撕包菜:13元,米飯:2元,紅燒肉:22.5元");
    float result = 0;
    while (matcher.find()) {
        String moneyStr = matcher.group(1);
        result += Float.parseFloat(moneyStr);
        System.out.println(moneyStr);
    }
    System.out.println("result: " + result);
}

執行結果:

image-20210918111921852

五、使用表達式替換字符串

法一(常用)

使用String類的成員函數String replaceAll(String regex, String replacement),其中

  1. 參數1為匹配模式
  2. 參數2位用於替換的字符串

例如使用正則表達式將字符串中所有的空白字符替換為,,此時的匹配模式為\s+,代碼實例如下:

@Test
public void t6() {
    String str = "123 wej  1jwe         315";
    String result = str.replaceAll("\\s+", ", ");
    System.out.println("result: " + result);
}

運行結果:

image-20210918114919404

法二

第二種方法既是使用String類的成員函數replaceAll的實現方式,即:

//replaceAll源碼
public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

示例如下:

@Test
public void t7() {
    String str = "123 wej  1jwe         315";
    Pattern pattern = Pattern.compile("\\s+");
    Matcher matcher = pattern.matcher(str);
    String result = matcher.replaceAll(", ");
    System.out.println("result: " + result);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM