java 正則表達(dá)式

java 正則表達(dá)式

正則表達(dá)式是一個(gè)非常強(qiáng)大的字符串處理工具,通過一種特殊的語法來描述一種模式,再通過模式可以完成字符串的匹配,萃取,替換等操作

簡(jiǎn)例

要判斷一個(gè)字符串是否是一個(gè)郵箱,可能需要很多的判斷邏輯,使用則表達(dá)式,只需要下面代碼即可

Pattern pattern = Pattern.compile("^([a-z0-9._%+-]+)@([a-z0-9.-]+)\\.[a-z]{2,4}$");
Matcher matcher = pattern.matcher("hatlonely@foxmail.com");
assertTrue(matcher.matches());

主要有 Pattern 對(duì)象和 Matcher 對(duì)象

  • Pattern: 模式對(duì)象
  • Matcher: 匹配的結(jié)果

部分匹配與完全匹配

Matcher 提供 matches 方法用于完全匹配,find 方法用于部分匹配,還提供 asPredicate 方法返回一個(gè)部分匹配的謂詞

Pattern 提供一個(gè)靜態(tài)方法 matches 用于完全匹配,這個(gè)方法會(huì)臨時(shí)構(gòu)造 Pattern 對(duì)象,如果 Pattern 會(huì)被多次重復(fù)使用,盡量別直接使用這種方法

assertTrue(Pattern.compile("hello").matcher("hello").matches());         // 完全匹配
assertTrue(Pattern.compile("hello").matcher("hello world").find());      // 部分匹配
assertTrue(Pattern.compile("hello").asPredicate().test("hello world"));  // 部分匹配
assertTrue(Pattern.matches("hello", "hello"));                           // 完全匹配

通配符

符號(hào) 含義
c 匹配單個(gè)字符 c
. 匹配所有單個(gè)字符,換行符 \n 除外
^ 匹配字符串開始
$ 匹配字符串結(jié)束
\b 匹配字符界,字符和空白之間
\B 匹配非字符界,字符和空白之間
| 匹配前面表達(dá)式或者后面表達(dá)式
[charset] 匹配任意括號(hào)內(nèi)的字符,可用 - 表示范圍,[a-z] 表示所有小寫字母
[^charset] 匹配任意括號(hào)外的字符
\d 匹配數(shù)字,相當(dāng)于 [0-9]
\D 匹配非數(shù)字,相當(dāng)于 [^0-9]
\s 匹配空白符,相當(dāng)于 [ \f\n\r\t\v]
\S 匹配非空白符,相當(dāng)于 [^ \f\n\r\t\v]
\f 匹配換頁(yè)符
\n 匹配換行符
\r 匹配回車
\t 匹配字表符
\v 匹配垂直制表符
\w 匹配字符類字符,包括下劃線,相當(dāng)于 [A-Za-z0-9_]
\W 匹配非字符類字符,[^A-Za-z0-9_]
\u 匹配四位十六進(jìn)制數(shù)表示的 Unicode 字符,\u00A9 例如匹配 ?
\x 匹配兩位十六進(jìn)制數(shù)表示的 ascii 碼
限定符 含義
* 匹配前面字符或表達(dá)式 0 次或多次
+ 匹配前面字符或表達(dá)式 1 次或多次
? 匹配前面字符或表達(dá)式 0 次或1次,跟著其他限定詞后表示非貪婪匹配
{n} 匹配前面字符或表達(dá)式 n 次
{n,} 匹配前面字符或表達(dá)式至少 n 次
{n,m} 匹配前面字符或表達(dá)式至少 n 次,至多 m 次
assertTrue(Pattern.matches("[0-9]*", ""));
assertTrue(Pattern.matches("[0-9]?", ""));
assertTrue(Pattern.matches("[0-9]?", "1"));
assertTrue(Pattern.matches("[0-9]+", "123"));
assertTrue(Pattern.matches("[0-9]{3}", "123"));
assertTrue(Pattern.matches("[0-9]{3,4}", "123"));
assertTrue(Pattern.matches("[0-9]{3,4}", "1234"));
assertTrue(Pattern.matches("[0-9]{3,}", "1234"));
assertTrue(Pattern.matches("\\d+", "123"));
assertTrue(Pattern.matches("\\s+", " \t"));
assertTrue(Pattern.matches("\\w+", "abc"));
assertTrue(Pattern.matches("(f|z)oo", "foo"));
assertTrue(Pattern.matches("(f|z)oo", "zoo"));
assertTrue(Pattern.matches(".*", "any string"));

捕獲分組

支持用小括號(hào) () 將模式分組,Matcher 提供 group 方法獲取分組的內(nèi)容

符號(hào) 含義
(pattern) 匹配分組并且捕獲子表達(dá)式
(?:pattern) 匹配分組但是不捕獲子表達(dá)式

使用 groupCount 獲取捕獲分組的數(shù)量,由于下面例子中模式串中沒有小括號(hào),所以沒有捕獲的分組

Pattern pattern = Pattern.compile("^[a-z0-9]+@[a-z0-9.]+[.][a-z]{2,4}$");
Matcher matcher = pattern.matcher("hatlonely@foxmail.com");
assertTrue(matcher.matches());
assertEquals(matcher.groupCount(), 0);

使用 group 方法獲取分組的內(nèi)容,分組的編號(hào)以左括號(hào)為準(zhǔn),gruop(i) 返回第 i 個(gè)分組,group(0) 代表整個(gè)匹配串

Pattern pattern = Pattern.compile("^([a-z0-9]+)@(([a-z0-9.]+)[.]([a-z]{2,4}))$");
Matcher matcher = pattern.matcher("hatlonely@foxmail.com");
assertTrue(matcher.matches());
assertEquals(matcher.groupCount(), 4);
assertEquals(matcher.group(), "hatlonely@foxmail.com");
assertEquals(matcher.group(1), "hatlonely");
assertEquals(matcher.group(2), "foxmail.com");
assertEquals(matcher.group(3), "foxmail");
assertEquals(matcher.group(4), "com");

可以用 ?: 阻止捕獲,如下面代碼所示,foxmail.com 就沒有被捕獲

Pattern pattern = Pattern.compile("^([a-z0-9]+)@(?:([a-z0-9.]+)[.]([a-z]{2,4}))$");
Matcher matcher = pattern.matcher("hatlonely@foxmail.com");
assertTrue(matcher.matches());
assertEquals(matcher.groupCount(), 3);
assertEquals(matcher.group(), "hatlonely@foxmail.com");
assertEquals(matcher.group(0), "hatlonely@foxmail.com");
assertEquals(matcher.group(1), "hatlonely");
assertEquals(matcher.group(2), "foxmail");
assertEquals(matcher.group(3), "com");

預(yù)測(cè)

符號(hào) 含義
(?=pattern) 正向預(yù)測(cè),非捕獲匹配,匹配結(jié)束
(?!pattern) 反向預(yù)測(cè),非捕獲匹配,匹配結(jié)束
(?<=pattern) 正向預(yù)測(cè),非捕獲匹配,匹配開始
(?<!pattern) 反向預(yù)測(cè),非捕獲匹配,匹配開始

正向預(yù)測(cè)是指匹配開始或者結(jié)束的字符串需要匹配(或者反向預(yù)測(cè)不能匹配)分組,分組內(nèi)的模式僅用于預(yù)測(cè),不會(huì)出現(xiàn)在最終的匹配串中,這種匹配只能用于部分匹配,?=?! 匹配開始,?<=?<! 匹配結(jié)束

{
    Pattern pattern = Pattern.compile("Windows (?=95|98|NT|2000)");
    Matcher matcher = pattern.matcher("Windows 2000");
    assertTrue(matcher.find());
    assertEquals(matcher.group(), "Windows ");
    assertEquals(matcher.groupCount(), 0);
}
{
    Pattern pattern = Pattern.compile("Windows (?!95|98|NT|2000)");
    Matcher matcher = pattern.matcher("Windows vista");
    assertTrue(matcher.find());
    assertEquals(matcher.group(), "Windows ");
    assertEquals(matcher.groupCount(), 0);
}
{
    Pattern pattern = Pattern.compile("(?<=95|98|NT|2000) Windows");
    Matcher matcher = pattern.matcher("2000 Windows");
    assertTrue(matcher.find());
    assertEquals(matcher.group(), " Windows");
    assertEquals(matcher.groupCount(), 0);
}
{
    Pattern pattern = Pattern.compile("(?<!95|98|NT|2000) Windows");
    Matcher matcher = pattern.matcher("vista Windows");
    assertTrue(matcher.find());
    assertEquals(matcher.group(), " Windows");
    assertEquals(matcher.groupCount(), 0);
}

反向引用

符號(hào) 含義
\1 匹配捕獲匹配到的反向引用,\2 表示第二個(gè)反向引用

前面通過捕獲獲得的分組可以再后面引用,比如 (\w+) \1 表示兩個(gè)重復(fù)的單詞

assertTrue(Pattern.matches("(\\w+) \\1", "ab ab"));
assertTrue(Pattern.matches("(\\w+) \\1", "abc abc"));
assertFalse(Pattern.matches("(\\w+) \\1", "abc def"));

正則替換

StringPattern 都提供了 replaceAllreplaceFirst 方法來作正則替換,替換串中可以 $i 來獲取正則匹配捕獲的分組

Pattern pattern = Pattern.compile("^([a-z0-9]+)@(?:([a-z0-9.]+)[.]([a-z]{2,4}))$");
assertEquals(pattern.matcher("hatlonely@foxmail.com").replaceAll(
        "$0 $1 $2 $3"
), "hatlonely@foxmail.com hatlonely foxmail com");

assertEquals("hatlonely@foxmail.com".replaceAll(
        "^([a-z0-9]+)@(?:([a-z0-9.]+)[.]([a-z]{2,4}))$", "$0 $1 $2 $3"
), "hatlonely@foxmail.com hatlonely foxmail com");

搜索所有匹配

每次 find 調(diào)用都會(huì)匹配目標(biāo)串中的一個(gè)匹配,通過多次 find 調(diào)用,可以找出目標(biāo)串中所有的匹配

String str = "abab x acac y aeae";
Pattern pattern = Pattern.compile("(\\w+)\\1");
Matcher matcher = pattern.matcher(str);

List<String> li = new ArrayList<>();
while (matcher.find()) {
    li.add(matcher.group());
    assertThat(str.substring(matcher.start(), matcher.end()), equalTo(matcher.group()));
}
assertThat(li, equalTo(List.of("abab", "acac", "aeae")));

鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。