Java里正則表達式(包括一些高級用法)


有些內容只有在 Java 里面才能使用。 ------原文作者:逗號 (他不高興發博客)

## 字符種類

部分使用頻率幾乎為 0 的這里不會提及(比如 \x 之流)

### 普通

| | 含義 | 助記 |
| ---- | ------------------------------------- | ----- |
| \s | 非空白 | space |
| \s | 空白 | |
| \d | 數字 | digit |
| \D | 非數字 | |
| [] | 自定義字符種類可使用 ^ \| && 隨意組合 | |

### 特別

| | 含義 | 助記 |
| ------- | ------------------------------------------------------------ | ---------- |
| \h | 橫向字符 | horizontal |
| \h | 非橫向字符 | |
| \v | 縱向字符(比如說換行符) | vertical |
| \V | 非縱向字符 | |
| \w | 單詞字符(包括 - _) | word |
| \W | 非單詞字符 | |
| \p{XXX} | POSIX,這個並不常用,在有些時候會方便,Character 有很多 is開頭的方法,將方法名中的`is`替換為`Java`可直接使用進行字符匹配:\p{javaLowerCase} | posix |
| \Q | 字符轉義開始符 | |
| \E | 字符轉義結束符,這兩個符號之間的內容全部按照字面量處理,里面是所有字符都不會有什么含義,比如 . 就是 .,\s 必須匹配\s,而不是匹配空白。 | |

## 量詞

| | 含義 | 助記 |
| ----- | ------------- | ---- |
| ? | 0個或者1個 | |
| * | 0個或多個 | |
| + | 1個或多個 | |
| {m} | m個 | |
| {m,n} | 介於m~n個之間 | |

`?`修飾在量詞之后,表盡可能少的匹配!

## 邊界

### 普通

| | 含義 | 助記 |
| ---- | ------------ | ---- |
| ^ | 字符開始位置 | |
| $ | 字符結束位置 | |

### 特別

| | 含義 | 助記 |
| ---- | ------------------------------ | ---- |
| \b | 單詞邊界,單詞的最前面和最后面 | |
| \B | 非字符串邊界 | |

下面的內容普通人基本上就已經不管了!

## 分組捕獲

正則表達式中,每出現一對括號就是新建了個新的組。比如:`(\\w+)|(\\d+)`

正則表達式的組可以用使用索引進行引用,形式為:`$index`

`$0` 默認指向原來的全部字符

然后索引遞增規律如下:

`((a)|(bc))`

`$1` 指向 `((a)|(bc))` 匹配的內容

`$2` 指向 `(a)` 匹配的內容

`$3` 指向 `(bc)` 匹配的內容

然而當正則復雜之后,改動將會對索引有較大影響,也不方便計算索引,此時,你可以為組制定名稱:

比如匹配字符串:`a=123,b=456`中間的鍵值,使用索引,需要寫成:`(\\w+)=(\\S+)`,然后使用`$1`指向 key,使用 `$2` 指向 value。

我們可以將正則改為:`(?<key>\\w+)=(?<value>\\S+)`,上述表達式使用 `?<name>` 的形式在正則中為組定義名稱。

## 引用分組

在 Java 中,你可以在兩種地方使用引用:

* 正則表達式中

匹配 `xxx-xxx` 字符 `-` 兩邊的內容相同,使用索引引用前面的組(`\\index`):

```regexp
(\\w+)-\\1
```

使用名字引用前面的組:

```regexp
(?<content>\\w+)-\\k<content>
```

* 在 Java 的字符串替換中

Markdown 中的字符串轉為斜線的html:

```java
"*name*".replaceAll("\\*(?<content>\\w+)\\*", "<em>$1</em>")
"*name*".replaceAll("\\*(?<content>\\w+)\\*", "<em>${content}</em>")
```

## 模式

你可以在構造 `Pattern`時設定模式:

```Java
Pattern.compile("abc", Pattern.CASE_INSENSITIVE)
```

模式可以自行到 `Pattern`下查看,這里只說使用方式,在組開頭使用 `?flags:`的方式聲明模式,比如:

匹配單詞,不區分大小寫

```regex
(?i:\\w+)
```

記住`i`(忽略大小寫)、`s`(. 匹配全部字符)即可,其他基本不用。

## 前瞻后顧

前瞻后顧,是正則表達式中的高級技巧,主要有5種:

> 注意:雖然這貨也有括號,但是這貨只算個條件,並不會捕獲任何內容,也不會影響索引

### 前瞻

前瞻中不帶`<`,並且只影響前面的表達式,意思就是偷偷往前看一下(這看一下沒有限制的,可以看到結尾)。

* `exp1(?=exp2)`

尋找后面是 exp2 的 exp1

* `exp1(?!exp2)`

### 后顧

* `(?<=exp1)exp2`

匹配 exp1 后面的 exp2,前面沒有exp1的內容將被忽略,比如,替換`abcba`替換`c`后面的`b`為 `xxx`,需要寫為:

```java
"abcba".replaceAll("(?<=c)b", "xxx")
```

`a`后面的`b`則不受影響。

> 注意:正則表達式`(?<=c)b`不會匹配字符串`cb`,意思就是:
>
> ```java
> assertFalse("cb".matches("(?<=c)b"));
> assertFalse("b".matches("(?<=c)b"));
> assertTrue("cb".matches("c(?<=c)b"));
> ```

* `(?<!exp1)exp2`

后顧中帶有 `<` ,並且只影響后面的表達式,也就是說,你如果寫成這樣:`exp2(?<=exp1)`,是沒什么卵用的。

## 牛刀小試

以下所有內容只能使用`String#repalceAll`或者`String#matches`完成。

### 手機號遮罩

將`11`位手機號除前4位之外,其他的使用`*`替換。

### 格式化數字

例如:`1234567890` 使用正則替換之后,變為 `1,234,567,890`。

### Trim 字符串

使用正則去除字符串開始和結束的空白字符。

### 去除數字結尾的`0`

`1234.4500`應該處理為`1234.45`,`1234.00`應該處理為`1234`。

### 處理文檔

將字符串的`* 測試 * ** 測試 **`的使用單個`*`包圍的內容兩邊分別加上`<h1>`、`</h1>`,不能影響兩個`**`包圍的內容。

### 測試某個字符串是不是合法的Java標識符

### 測試`IPv4`

已知`IPv4`中每一段的數字需要介於0~255,測試某個字符串是否是合法的`IPv4`表達式。

### 去除`//`注釋

已知`Java`中可以使用`//` 進行單行注釋,請去除一段代碼中的這種注釋。

### 去除`/* 內容 */`注釋

已知`Java`中可以使用`/* */` 進行多行注釋,請去除代碼中的這種注釋。

 


免責聲明!

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



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