一、正則表達式介紹
一個正則表達式是一種從左到右匹配主體字符串的模式。
“Regular expression”這個詞比較拗口,我們常使用縮寫的術語“regex”或“regexp”。
正則表達式可以從一個基礎字符串中根據一定的匹配模式替換文本中的字符串、驗證表單、提取字符串等等。
二、基本語法
2.1 匹配符號
符號 | 說明 |
---|---|
\b | 匹配邊界,即字與空格間的位置。(\b所在位置的左右兩個字符有一個是\W,即不是A-Z,a-z,0-9,_) |
\B | 非單詞邊界匹配。 |
\d | 匹配0-9中任意一個數字字符 |
\D | 匹配除0-9外的非數字字符,等同于[^\d]
|
\f | 匹配一個換頁符 |
\n | 匹配一個換行符 |
\p | 匹配 CR/LF(等同于 \r\n ),用來匹配 DOS 行終止符 |
\r | 匹配一個回車符 |
\s | 匹配空格、制表符、換行符等空白字符 |
\S | 匹配非空白字符 |
\t | 匹配一個制表符 |
\v | 匹配一個垂直制表符 |
\w | 匹配A-Z,a-z,0-9和_中任意一個 |
\W | 非單詞字符,等同于: [^\w]
|
. | 匹配一個任意的字符,不匹配換行符。如 .* 匹配任意字符串 |
\p{L} | 表示Unicode字母 |
\p{N} | 表示Unicode數字 |
2.2 特殊含義符號
符號 | 說明 |
---|---|
\ | 轉義,用于指定 { } [ ] / \ + * . $ ^|?這些特殊字符。如果想要匹配這些特殊字符則要在其前面加上反斜線 \。 |
^ | 表示一行的開頭,而在[]內表示取反 |
$ | 匹配一行的結束,如 R$ 表示以R結尾的行 |
[] | 表示匹配某個范圍內的字符,正則表達式特殊字符被放到中括號中,失去特殊含義,除了"^"和"-" 。如[a-z]表示匹配一個小寫字母;[^a-z]表示匹配一個非小寫字母。 |
() | 作為一個整體進行匹配,如(ab)+表示匹配ab一次或多次,如 (cat|dog)+ 表達匹配一次或多次cat或dog |
| | 或運算符就表示或,用作判斷條件。 |
2.3 量詞
通過量詞可以設置一個內容出現的次數 ,量詞只對它前邊的一個內容起作。
符號 | 說明 |
---|---|
{3} | 匹配三個 |
{3,6} | 匹配3到6個(默認貪婪模式,往多的匹配) |
{3,6}? | 匹配3到6個,?表示非貪婪模式,即匹配最少個數。 |
? | 匹配前面元字符0次或1次,相當于{0,1};也會被用來表示懶惰匹配,如<.+?> 可以匹配html標簽 |
+ | 一個或多個,相當于{1,} |
* | 匹配任意個(貪心匹配),相當于{0,} |
2.4 零寬斷言
先行斷言和后發斷言都屬于非捕獲簇(不捕獲文本 ,也不針對組合計進行計數)。
先行斷言用于判斷所匹配的格式是否在另一個確定的格式之前,匹配結果不包含該確定格式(僅作為約束)。
例如,我們想要獲得所有跟在 $
符號后的數字,我們可以使用正后發斷言 (?<=\$)[0-9\.]*
。
這個表達式匹配 $
開頭,之后跟著 0,1,2,3,4,5,6,7,8,9,.
這些字符可以出現大于等于 0 次。
零寬度斷言如下:
符號 | 描述 |
---|---|
?= | 正先行斷言-存在 |
?! | 負先行斷言-排除 |
?<= | 正后發斷言-存在 |
?<! | 負后發斷言-排除 |
2.4.1 ?=...
正先行斷言
?=...
正先行斷言,表示第一部分表達式之后必須跟著 ?=...
定義的表達式。
返回結果只包含滿足匹配條件的第一部分表達式。
定義一個正先行斷言要使用 (?=...)
。
如果將正先行斷言式放在匹配式的后面,則表示匹配式后需要滿足正先行斷言式。
如果將正先行斷言式放在匹配式的前面,則表示使用正先行斷言式對匹配到的結果進行篩選。
例:
現在有文本如下
The fat cat sat on the mat.
使用正先行斷言(T|t)he(?=\sfat)
進行正則匹配,即 The
和 the
后面緊跟著 (空格)fat
。也可以使用表達式(?=The\sfat)The
進行匹配。
最終得到匹配的文本如下
The
例:
至少一個大寫字母和一個小寫字母,可以使用表達式 (?=.*?[a-z])(?=.*?[A-Z]).+
2.4.2 ?!...
負先行斷言
負先行斷言 ?!
用于篩選所有匹配結果,篩選條件為 其后不跟隨著斷言中定義的格式。
正先行斷言
定義和 負先行斷言
一樣,區別就是 =
替換成 !
也就是 (?!...)
。
例:
有文本如下
The fat cat sat on the mat.
使用負先行斷言(T|t)he(?!\sfat)
進行正則匹配,即 The
和 the
后面沒有 (空格)fat
文本。
最終得到匹配的文本如下
the
2.4.3 ?<= ...
正后發斷言
正后發斷言 記作(?<=...)
用于篩選所有匹配結果,篩選條件為 其前跟隨著斷言中定義的格式。
如果將正后發斷言式放在匹配式的前面,則表示匹配式前需要滿足正后發斷言式。
如果將正后發斷言式放在匹配式的后面,則表示使用正后發斷言式對匹配到的結果進行篩選。
例:
表達式 `` 匹配 fat
和 mat
,且其前跟著 The
或 the
。
有文本如下
The fat cat sat on the mat.
使用正后發斷言(?<=The\s)(fat|mat)
進行正則匹配,即 fat
或 mat
前跟隨著 The文本。也可以使用匹配式(fat|mat)(?<=The\sfat)
進行匹配。
最終得到匹配的文本如下
fat
例:
匹配文本
我喜歡你
使用匹配式(?<=我)喜歡(?=你)
2.4.4 ?<!...
負后發斷言
負后發斷言 記作 (?<!...)
用于篩選所有匹配結果,篩選條件為 其前不跟隨著斷言中定義的格式。
例:
有文本如下
The fat cat sat on the mat.
使用正后發斷言(?<!The\s)(fat|mat)
進行正則匹配,即 fat
或 mat
前不跟隨著 The文本。
最終得到匹配的文本如下
mat
2.5 標志
標志也叫模式修正符,因為它可以用來修改表達式的搜索結果。
這些標志可以任意的組合使用,它也是整個正則表達式的一部分。
標志 | 描述 |
---|---|
i | 忽略大小寫。 |
g | 全局搜索。 |
m | 多行修飾符:錨點元字符 ^ $ 工作范圍在每行的起始。 |
s | dotall |
u | Unicode |
y | 粘性(stucky) |
2.5.1 全局搜索 (Global search)
修飾符 g
常用于執行一個全局搜索匹配,即(不僅僅返回第一個匹配的,而是返回全部)。
例:
表達式 /.(at)/g
表示搜索 任意字符(除了換行)+ at
,并返回全部結果。
2.5.2 忽略大小寫 (Case Insensitive)
修飾語 i
用于忽略大小寫。
例:
如,表達式 /The/gi
表示在全局搜索 The
,在后面的 i
將其條件修改為忽略大小寫,則變成搜索 the
和 The
。
2.5.3 多行修飾符 (Multiline)
多行修飾符 m
常用于執行一個多行匹配。
像之前介紹的 ^和$
用于檢查格式是否是在待檢測字符串的開頭或結尾。但我們如果想要它在每行的開頭和結尾生效,我們需要用到多行修飾符 m
。
例如,表達式 /at(.)?$/gm
表示小寫字符 a
后跟小寫字符 t
,末尾可選除換行符外任意字符。根據 m
修飾符,現在表達式匹配每行的結尾。
2.6 捕獲組
2.6.1 捕獲分組
在正則表達式中還提供了一種將表達式分組的機制,當使用分組時,除了獲得整個匹配。還能在匹配中選擇每一個分組。
要實現分組,使用()即可。
例:
文本如下
張三:0571-88551166
使用表達式/(\d{4})-(\d{8})/g
,匹配得到文本 0571-8855116.
那么這個文本實際分為了兩組,第一組為0571,第二組為8855116.
2.6.2 非捕獲分組
有時候,我們并不需要捕獲某個分組的內容,但是又想使用分組的特性。
這時候就可以使用非捕獲分組(?:表達式)
,從而不捕獲數據,還能使用分組的功能。
2.6.3 分組回溯引用
正則表達式提供了一種引用之前匹配分組的機制,有些時候,我們或許會尋找到一個子匹配,該匹配接下來會再次出現。
例:
文本如下
<font>提示</font>
<font>提示</bar>
希望匹配正確的標簽,可以使用 <(\w+?)>(.*?)<\/\1>
這里\1表示第一個括號中的內容,這樣就可以使用回溯分組調用,調用第一個括號的內容。
最終匹配到了正確的文本
<font>提示</font>
注:在java程序中,可以使用 $n 來使用捕獲的第n個內容,如
string.replaceAll("<(.*)>", "$1 ");
三、經典正則表達式
由26個字母和數字組成的字符串:
^[A-Za-z0-9]+\$
匹配中文字符:
[\u4e00-\u9fa5]
沒有空字符的且以tmp結尾的文件(^在中括號中表示取反,在中括號外表示開頭):
[^ ]*.tmp
匹配html標簽:
<.+?>
只需要添加懶惰匹配符號?,讓<>來匹配每個標簽匹配顏色標簽符,如#ffffff:
#[a-fA-F0-9]{6}\b
,添加\b是為了防止#ffffffff這種被識別為顏色標簽符正整數*:
^\d+$
負整數:
^-\d+$
國內電話號碼:
\d{3}-\d{8}|\d{4}-\d{7}
手機國家號:
^+?[\d\s]{3,}$
手機號:
^+?[\d\s]+(?[\d\s]{10,}$
整數:
^-?\d+$
用戶名:
^[\w\d_.]{4,16}$
數字和英文字母:
^[a-zA-Z0-9]*$
數字和應為字母和空格:
^[a-zA-Z0-9 ]*$
密碼(至少一個大寫字母、至少一個小寫字母、至少一個數字、至少8個字符):
/(?=.*?[a-z])(?=.*?[A-Z])(?=.*?(\d)).{8,}/g
密碼:
^(?=^.{6,}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$
郵箱:
^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$
IP4 地址:
^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$
純小寫字母:
^([a-z])*$
純大寫字母:
^([A-Z])*$
URL:
^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$
VISA 信用卡號:
^(4[0-9]{12}(?:[0-9]{3})?)*$
日期 (MM/DD/YYYY):
^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$
日期 (YYYY/MM/DD):
^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$
MasterCard 信用卡號:
^(5[1-5][0-9]{14})*$
IP地址(需要分為四段):
0-99:[1-9]?\d
100-199:1\d{2}
200-249:2[0-4]\d
250-256:25[0-5]
(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])