1.20 正则表达式详解
正則表達式(Regular Expression)又稱正規表示法、常規表示法,在代碼中常簡寫為 regex、regexp 或 RE,它是計算機科學的一個概念。
正則表達式是一個強大的字符串處理工具,可以對字符串進行查找、提取、分割、替換等操作,是一種可以用于模式匹配和替換的規范。一個正則表達式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)組成的文字模式,它用以描述在查找文字主體時待匹配的一個或多個字符串。
String 類里也提供了如下幾個特殊的方法。
- boolean matches(String regex):判斷該字符串是否匹配指定的正則表達式。
- String replaceAll(String regex, String replacement):將該字符串中所有匹配 regex
的子串替換成 replacement。 - String replaceFirst(String regex, String replacement):將該字符串中第一個匹配
regex 的子串替換成 replacement。 - String[] split(String regex):以 regex 作為分隔符,把該字符串分割成多個子串。
上面這些特殊的方法都依賴于 Java 提供的正則表達式支持,除此之外,Java 還提供了 Pattern 和 Matcher 兩個類專門用于提供正則表達式支持。
很多讀者都會覺得正則表達式是一個非常神奇、高級的知識,其實正則表達式是一種非常簡單而且非常實用的工具。正則表達式是一個用于匹配字符串的模板。實際上,任意字符串都可以當成正則表達式使用。例如“abc”,它也是一個正則表達式,只是它只能匹配“abc”字符串。
如果正則表達式僅能匹配“abc”這樣的字符串,那么正則表達式也就不值得學習了。正則表達式作為一個用于匹配字符串的模板,將某個字符模式與所搜索的字符串進行匹配。本文簡單了解一下如何使用正則表達式來操作字符串。
正則表達式支持字符
創建正則表達式就是創建一個特殊的字符串。正則表達式所支持的合法字符如表 1 所示。
表 1 正則表達式所支持的合法字符
| X | 字符x(x 可代表任何合法的字符) |
| \0mnn | 八進制數 0mnn 所表示的字符 |
| \xhh | 十六進制值 0xhh 所表示的字符 |
| \uhhhh | 十六進制值 0xhhhh 所表示的 Unicode 字符 |
| \t | 制表符(“\u0009”) |
| \n 新行 | (換行)符(‘\u000A’) |
| \r 回車符 | (‘\u000D’) |
| \f | 換頁符(‘\u000C’) |
| \a | 報警(bell)符(‘\u0007’) |
| \e | Escape 符(‘\u001B’) |
| \cx | x 對應的的控制符。例如,\cM匹配 Ctrl-M。x 值必須為 A~Z 或 a~z 之一。 |
除此之外,正則表達式中有一些特殊字符,這些特殊字符在正則表達式中有其特殊的用途,比如前面介紹的反斜線\。
如果需要匹配這些特殊字符,就必須首先將這些字符轉義,也就是在前面添加一個反斜線\。正則表達式中的特殊字符如表 2 所示。
表 2 正則表達式中的特殊字符
| $ | 匹配一行的結尾。要匹配 $ 字符本身,請使用$ |
| ^ | 匹配一行的開頭。要匹配 ^ 字符本身,請使用^ |
| () | 標記子表達式的開始和結束位置。要匹配這些字符,請使用(和) |
| [] | 用于確定中括號表達式的開始和結束位置。要匹配這些字符,請使用[和] |
| {} | 用于標記前面子表達式的出現頻度。要匹配這些字符,請使用{和} |
| * | 指定前面子表達式可以出現零次或多次。要匹配 * 字符本身,請使用* |
| + | 指定前面子表達式可以出現一次或多次。要匹配 + 字符本身,請使用+ |
| ? | 指定前面子表達式可以出現零次或一次。要匹配 ?字符本身,請使用? |
| . | 匹配除換行符\n之外的任何單字符。要匹配.字符本身,請使用. |
| \ | 用于轉義下一個字符,或指定八進制、十六進制字符。如果需匹配\字符,請用\ |
| | | 指定兩項之間任選一項。如果要匹配丨字符本身,請使用| |
將上面多個字符拼起來,就可以創建一個正則表達式。例如:
"\u0041\\\\" // 匹配 A\ "\u0061\t" // 匹配a<制表符> "\\?\\[" // 匹配?[注意:可能大家會覺得第一個正則表達式中怎么有那么多反斜杠?這是由于 Java 字符串中反斜杠本身需要轉義,因此兩個反斜杠(\)實際上相當于一個(前一個用于轉義)。
上面的正則表達式依然只能匹配單個字符,這是因為還未在正則表達式中使用“通配符”,“通配符”是可以匹配多個字符的特殊字符。正則表達式中的“通配符”遠遠超出了普通通配符的功能,它被稱為預定義字符,正則表達式支持如表 3 所示的預定義字符。
表 3 預定義字符
| . | 可以匹配任何字符 |
| \d | 匹配 0~9 的所有數字 |
| \D | 匹配非數字 |
| \s | 匹配所有的空白字符,包括空格、制表符、回車符、換頁符、換行符等 |
| \S | 匹配所有的非空白字符 |
| \w | 匹配所有的單詞字符,包括 0~9 所有數字、26 個英文字母和下畫線_ |
| \W | 匹配所有的非單詞字符 |
上面的 7 個預定義字符其實很容易記憶,其中:
- d 是 digit 的意思,代表數字。
- s 是 space 的意思,代表空白。
- w 是 word 的意思,代表單詞。
- d、s、w 的大寫形式恰好匹配與之相反的字符。
有了上面的預定義字符后,接下來就可以創建更強大的正則表達式了。例如:
c\wt // 可以匹配cat、cbt、cct、cOt、c9t等一批字符串
\d\d\d-\d\d\d-\d\d\d\d // 匹配如 000-000-0000 形式的電話號碼
在一些特殊情況下,例如,若只想匹配 a~f 的字母,或者匹配除 ab 之外的所有小寫字母,或者匹配中文字符,上面這些預定義字符就無能為力了,此時就需要使用方括號表達式,方括號表達式有如表 4 所示的幾種形式。
表 4 方括號表達式
方括號表達式比前面的預定義字符靈活多了,幾乎可以匹配任何字符。例如,若需要匹配所有的中文字符,就可以利用 [\u0041-\u0056] 形式——因為所有中文字符的 Unicode 值是連續的,只要找出所有中文字符中最小、最大的 Unicode 值,就可以利用上面形式來匹配所有的中文字符。
正則表達式還支持圓括號,用于將多個表達式組成一個子表達式,圓括號中可以使用或運算符|。例如,正則表達式“((public)|(protected)|(private))”用于匹配 Java 的三個訪問控制符其中之一。
除此之外,Java 正則表達式還支持如表 5 所示的幾個邊界匹配符。
表 5 邊界匹配符
| ^ | 行的開頭 |
| $ | 行的結尾 |
| \b | 單詞的邊界 |
| \B | 非單詞的邊界 |
| \A | 輸入的開頭 |
| \G | 前一個匹配的結尾 |
| \Z | 輸入的結尾,僅用于最后的結束符 |
| \z | 輸入的結尾 |
前面例子中需要建立一個匹配 000-000-0000 形式的電話號碼時,使用了 \d\d\d-\d\d\d-\d\d\d\d 正則表達式,這看起來比較煩瑣。實際上,正則表達式還提供了數量標識符,正則表達式支持的數量標識符有如下幾種模式。
- Greedy(貪婪模式):數量表示符默認采用貪婪模式,除非另有表示。貪婪模式的表達式會一直匹配下去,直到無法匹配為止。如果你發現表達式匹配的結果與預期的不符,很有可能是因為你以為表達式只會匹配前面幾個字符,而實際上它是貪婪模式,所以會一直匹配下去。
- Reluctant(勉強模式):用問號后綴(?)表示,它只會匹配最少的字符。也稱為最小匹配模式。
- Possessive(占有模式):用加號后綴(+)表示,目前只有 Java 支持占有模式,通常比較少用。
三種模式的數量表示符如表 6 所示。
表 6 三種模式的數量表示符
關于貪婪模式和勉強模式的對比,看如下代碼:
當從“hello java!”字符串中查找匹配\\w*子串時,因為\w*使用了貪婪模式,數量表示符*會一直匹配下去,所以該字符串前面的所有單詞字符都被它匹配到,直到遇到空格,所以替換后的效果是“■,Java!”;如果使用勉強模式,數量表示符*會盡量匹配最少字符,即匹配 0 個字符,所以替換后的結果是“■hello,java!”。
總結
以上是生活随笔為你收集整理的1.20 正则表达式详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1.19 String、StringBu
- 下一篇: 1.21 Pattern类和Matche