前言
分析數(shù)據(jù)的前提是要準(zhǔn)確提煉數(shù)據(jù),而正則表達(dá)式就是很好的提煉數(shù)據(jù)工具。
本文旨在讓讀者快速地了解正則表達(dá)式的基本規(guī)則和特性。本文雖說簡單,但其實(shí)也不簡單,需要反復(fù)觀看記憶。
本文轉(zhuǎn)載于資料[1],每個(gè)例子我基本都測試了一遍。也加了一些內(nèi)容和標(biāo)記,方便更好理解。
目錄
[TOC]
什么是正則表達(dá)式 ?
正則表達(dá)式是一種被用于從文本中檢索符合某些特定模式的文本。
正則表達(dá)式是從左到右來匹配一個(gè)字符串的。由于"Regular Expression" 這個(gè)詞太長了,我們通常使用它的縮寫 "regex" 或者 "regexp"。
正則表達(dá)式可以被用來替換字符串中的文本、驗(yàn)證表單、基于模式匹配從一個(gè)字符串中提取字符串等等。
想象一下,您正在編寫應(yīng)用程序,并且您希望在用戶選擇用戶名時(shí)設(shè)置規(guī)則。我們希望用戶名可以包含字母,數(shù)字,下劃線和連字符。為了讓它看起來不丑,我們還想限制用戶名中的字符數(shù)量。我們可以使用以下正則表達(dá)式來驗(yàn)證用戶名:

上面這個(gè)正則表達(dá)式可以匹配 john_doe,jo-hn_doe 和 john12_as。但是它不能匹配 Jo,因?yàn)樵撟址锩姘舜髮懽址?,并且它太短了?/p>
注:以下大部分例子為全局搜索,什么是全局搜索,請參考目錄5.2。
1. 基本匹配
正則表達(dá)式只是我們用于在文本中檢索字母和數(shù)字的模式。例如正則表達(dá)式 cat,表示: 字母 c 后面跟著一個(gè)字母 a,再后面跟著一個(gè)字母 t。
cat => The cat sat on the mat
正則表達(dá)式 123 會匹配字符串 "123"。通過將正則表達(dá)式中的每個(gè)字符逐個(gè)與要匹配的字符串中的每個(gè)字符進(jìn)行比較,來完成正則匹配。
正則表達(dá)式通常區(qū)分大小寫,因此正則表達(dá)式 Cat 與字符串 "cat" 不匹配。
Cat => The cat sat on the Cat
2. 元字符
元字符是正則表達(dá)式的基本組成元素。元字符在這里跟它通常表達(dá)的意思不一樣,而是以某種特殊的含義去解釋。有些元字符寫在方括號內(nèi)的時(shí)候有特殊含義。
元字符如下:
| 元字符 | 描述 |
|---|---|
| . | 匹配除換行符以外的任意字符。 |
| [ ] | 字符類,匹配方括號中包含的任意字符。 |
| [^ ] | 否定字符類。匹配方括號中不包含的任意字符 |
| * | 匹配前面的子表達(dá)式零次或多次 |
| + | 匹配前面的子表達(dá)式一次或多次 |
| ? | 匹配前面的子表達(dá)式零次或一次,或指明一個(gè)非貪婪限定符。 |
| {n,m} | 花括號,匹配前面字符至少 n 次,但是不超過 m 次。 |
| (xyz) | 字符組,按照確切的順序匹配字符xyz。 |
| | | 分支結(jié)構(gòu),匹配符號之前的字符或后面的字符。 |
| \ | 轉(zhuǎn)義符,它可以還原元字符原來的含義,允許你匹配保留字符 [ ] ( ) { } . * + ? ^ $ \ |
|
| ^ | 匹配行的開始 |
| $ | 匹配行的結(jié)束 |
2.1 英文句號
英文句號 . 是元字符的最簡單的例子。元字符 . 可以匹配任意單個(gè)字符。它不會匹配換行符和新行的字符。例如正則表達(dá)式 .ar,表示:
任意字符后面跟著一個(gè)字母 a,再后面跟著一個(gè)字母 r。
.ar => The car parked in the garage.
2.2 字符集
字符集也稱為字符類。方括號被用于指定字符集。使用字符集內(nèi)的連字符來指定字符范圍。方括號內(nèi)的字符范圍的順序并不重要。
例如正則表達(dá)式 [Tt]he,表示: 大寫 T 或小寫 t ,后跟字母 h,再后跟字母 e。
[Tt]he => The car parked in the garage.
然而,字符集中的英文句號表示它字面的含義。正則表達(dá)式 ar[.],表示小寫字母 a,后面跟著一個(gè)字母 r,再后面跟著一個(gè)英文句號 . 字符。
ar[.] => A garage is a good place to park a car.
2.2.1 否定字符集
一般來說插入字符 ^ 表示一個(gè)字符串的開始,但是當(dāng)它在方括號內(nèi)出現(xiàn)時(shí),它會取消字符集。例如正則表達(dá)式 [^c]ar,表示: 除了字母 c 以外的任意字符,后面跟著字符 a,再后面跟著一個(gè)字母 r。
[^c]ar => The car parked in the garage.
2.3 重復(fù)
以下元字符 +,* 或 ? 用于指定子模式可以出現(xiàn)多少次。這些元字符在不同情況下的作用不同。
2.3.1 星號
該符號 * 表示匹配上一個(gè)匹配規(guī)則的零次或多次。正則表達(dá)式 a* 表示小寫字母 a 可以重復(fù)零次或者多次。但是它如果出現(xiàn)在字符集或者字符類之后,它表示整個(gè)字符集的重復(fù)。
例如正則表達(dá)式 [a-z]*,表示: 一行中可以包含任意數(shù)量的小寫字母。
[a-z]* => The car parked in the garage #21 .
該 * 符號可以與元符號 . 用在一起,用來匹配任意字符串 .*。該 * 符號可以與空格符 \s 一起使用,用來匹配一串空格字符。
例如正則表達(dá)式 \s*cat\s*,表示:
零個(gè)或多個(gè)空格,后面跟小寫字母 c,再后面跟小寫字母 a,再再后面跟小寫字母 t,后面再跟零個(gè)或多個(gè)空格。
\s*cat\s* => The fat cat sat on the cat.
\s*cat\s* => The fat catcatcat.
2.3.2 加號
該符號 + 匹配上一個(gè)字符的一次或多次。例如正則表達(dá)式 c.+t,表示: 一個(gè)小寫字母 c,后跟任意數(shù)量的字符,后跟小寫字母 t。
c.+t => The fat cat sat on the mat.
c.+t => cat ct
c.+t => ct
注意比較第二個(gè)和第三個(gè)例子。
2.3.3 問號
在正則表達(dá)式中,元字符 ? 用來表示前一個(gè)字符是可選的。該符號匹配前一個(gè)字符的零次或一次。
例如正則表達(dá)式 [T]?he,表示:
可選的大寫字母 T,后面跟小寫字母 h,后跟小寫字母 e。
[T]he => The car is parked in the garage.
[T]?he => The car is parked in the garage.
[T]?he => .he ahe TThe
2.4 花括號
在正則表達(dá)式中花括號(也被稱為量詞 ?)用于指定字符或一組字符可以重復(fù)的次數(shù)。例如正則表達(dá)式 [0-9]{2,3},表示: 匹配至少2位數(shù)字但不超過3位(0到9范圍內(nèi)的字符)。
[0-9]{2,3} => The number was 9.9997 but we rounded it off to 10.0.
我們可以省略第二個(gè)數(shù)字。例如正則表達(dá)式 [0-9]{2,},表示:
匹配2個(gè)或更多個(gè)數(shù)字。
如果我們也刪除逗號,則正則表達(dá)式 [0-9]{2},表示:
匹配正好為2位數(shù)的數(shù)字。
[0-9]{2,} => The number was 9.9997 but we rounded it off to 10.0.
[0-9]{2} => The number was 9.9997 but we rounded it off to 10.0.
這里因?yàn)槭侨炙阉?,所以比較起來沒有什么區(qū)別,如果我們關(guān)掉全局搜索,結(jié)果如下:
[0-9]{2,} => The number was 9.9997 but we rounded it off to 10.0.
[0-9]{2} => The number was 9.9997 but we rounded it off to 10.0.
這里再做一個(gè)對比:
[0-9]{2,3} => 2333
[0-9]{2,3} => 23333
這兩個(gè)例子開啟了全局搜索,可以發(fā)現(xiàn),這是優(yōu)先匹配最長的。并且每次匹配都會消耗字符串的,且消耗的是最長的。
2.5 字符組
字符組是一組寫在圓括號內(nèi)的子模式 (...)。正如我們在正則表達(dá)式中討論的那樣,如果我們把一個(gè)量詞放在一個(gè)字符之后,它會重復(fù)前一個(gè)字符。
但是,如果我們把量詞放在一個(gè)字符組之后,它會重復(fù)整個(gè)字符組。
例如正則表達(dá)式 (ab)* 表示匹配零個(gè)或多個(gè)的字符串 "ab"。我們還可以在字符組中使用元字符 |。例如正則表達(dá)式 (c|g|p)ar,表示: 小寫字母 c、g 或 p 后面跟字母 a,后跟字母 r。
(c|g|p)ar => The car is parked in the garage.
(c|g|p)ar => ar par
2.6 分支結(jié)構(gòu)
在正則表達(dá)式中垂直條 | 用來定義分支結(jié)構(gòu),分支結(jié)構(gòu)就像多個(gè)表達(dá)式之間的條件?,F(xiàn)在你可能認(rèn)為這個(gè)字符集和分支機(jī)構(gòu)的工作方式一樣。
但是字符集和分支結(jié)構(gòu)巨大的區(qū)別是字符集只在字符級別上有作用,然而分支結(jié)構(gòu)在表達(dá)式級別上依然可以使用。
例如正則表達(dá)式 (T|t)he|car,表示: 大寫字母 T 或小寫字母 t,后面跟小寫字母 h,后跟小寫字母 e 或小寫字母 c,后跟小寫字母 a,后跟小寫字母 r。
(T|t)he|car => The car is parked in the garage.
2.7 轉(zhuǎn)義特殊字符
正則表達(dá)式中使用反斜杠 \ 來轉(zhuǎn)義下一個(gè)字符。這將允許你使用保留字符來作為匹配字符 { } [ ] / \ + * . $ ^ | ?。在特殊字符前面加 \,就可以使用它來做匹配字符。
例如正則表達(dá)式 . 是用來匹配除了換行符以外的任意字符?,F(xiàn)在要在輸入字符串中匹配 . 字符,正則表達(dá)式 (f|c|m)at\.?,表示:
小寫字母 f、c 或者 m 后跟小寫字母 a,后跟小寫字母 t,后跟可選的 . 字符。
(f|c|m)at\.? => The fat cat sat on the mat.
2.8 定位符
在正則表達(dá)式中,為了檢查匹配符號是否是起始符號或結(jié)尾符號,我們使用定位符。
定位符有兩種類型:
- 第一種類型是
^檢查匹配字符是否是起始字符; - 第二種類型是
$,它檢查匹配字符是否是輸入字符串的最后一個(gè)字符。
2.8.1 插入符號
插入符號 ^ 符號用于檢查匹配字符是否是輸入字符串的第一個(gè)字符。如果我們使用正則表達(dá)式 ^a (如果a是起始符號)匹配字符串 abc,它會匹配到 a。
但是如果我們使用正則表達(dá)式 ^b,它是匹配不到任何東西的,因?yàn)樵谧址?abc 中 b 不是起始字符。
讓我們來看看另一個(gè)正則表達(dá)式 ^(T|t)he,這表示:
大寫字母 T 或小寫字母 t 是輸入字符串的起始符號,后面跟著小寫字母 h,后跟小寫字母 e。
(T|t)he => The car is parked in the garage.
^(T|t)he => The car is parked in the garage.
2.8.2 美元符號
美元 $ 符號用于檢查匹配字符是否是輸入字符串的最后一個(gè)字符。例如正則表達(dá)式 (at\.)$,表示:
小寫字母 a,后跟小寫字母 t,后跟一個(gè) . 字符,且這個(gè)匹配器必須是字符串的結(jié)尾。
(at\.) => The fat cat. sat. on the mat.
(at\.)$ => The fat cat sat on the mat.
3. 簡寫字符集
正則表達(dá)式為常用的字符集和常用的正則表達(dá)式提供了簡寫。簡寫字符集如下:
| 簡寫 | 描述 |
|---|---|
| . | 匹配除換行符以外的任意字符 |
| \w | 匹配所有字母和數(shù)字的字符: [a-zA-Z0-9_]
|
| \W | 匹配非字母和數(shù)字的字符: [^\w]
|
| \d | 匹配數(shù)字: [0-9]
|
| \D | 匹配非數(shù)字: [^\d]
|
| \s | 匹配空格符: [\t\n\f\r\p{Z}]
|
| \S | 匹配非空格符: [^\s]
|
4. 斷言
后行斷言和先行斷言有時(shí)候被稱為斷言,它們是特殊類型的 非捕獲組 (用于匹配模式,但不包括在匹配列表中)。當(dāng)我們在一種特定模式之前或者之后有這種模式時(shí),會優(yōu)先使用斷言。
例如我們想獲取輸入字符串 $4.44 and $10.88 中帶有前綴 $ 的所有數(shù)字。我們可以使用這個(gè)正則表達(dá)式 (?<=\$)[0-9\.]*,表示:
獲取包含 . 字符且前綴為 $ 的所有數(shù)字。
以下是正則表達(dá)式中使用的斷言:
| 符號 | 描述 |
|---|---|
| ?= | 正向先行斷言 |
| ?! | 負(fù)向先行斷言 |
| ?<= | 正向后行斷言 |
| ?<! | 負(fù)向后行斷言 |
4.1 正向先行斷言
正向先行斷言認(rèn)為第一部分的表達(dá)式必須是先行斷言表達(dá)式。返回的匹配結(jié)果僅包含與第一部分表達(dá)式匹配的文本。
要在一個(gè)括號內(nèi)定義一個(gè)正向先行斷言,在括號中問號和等號是這樣使用的 (?=...)。先行斷言表達(dá)式寫在括號中的等號后面。
例如正則表達(dá)式 (T|t)he(?=\sfat),表示: 匹配大寫字母 T 或小寫字母 t,后面跟字母 h,后跟字母 e。
在括號中,我們定義了正向先行斷言,它會引導(dǎo)正則表達(dá)式引擎匹配 The 或 the 后面跟著 fat。
(T|t)he(?=\sfat) => The fat cat sat on the mat.
(T|t)he(?=\sfat) => The thin cat sat on the mat.
從結(jié)果對比,可以看出,\sfat 是必須要有的,但匹配的結(jié)果不會顯示它。
4.2 負(fù)向先行斷言
當(dāng)我們需要從輸入字符串中獲取不匹配表達(dá)式的內(nèi)容時(shí),使用負(fù)向先行斷言。負(fù)向先行斷言的定義跟我們定義的正向先行斷言一樣,唯一的區(qū)別是不是等號 =,我們使用否定符號 !,例如 (?!...)。
我們來看看下面的正則表達(dá)式 (T|t)he(?!\sfat),表示: 從輸入字符串中獲取全部 The 或者 the 且不匹配 fat 前面加上一個(gè)空格字符。
(T|t)he(?!\sfat) => The fat cat sat on the mat.
這里可以看出,\sfat 是必須不能有的,但匹配的結(jié)果不會顯示它。
4.3 正向后行斷言
正向后行斷言是用于獲取在特定模式之前的所有匹配內(nèi)容。正向后行斷言表示為 (?<=...)。例如正則表達(dá)式 (?<=(T|t)he\s)(fat|mat),表示:
從輸入字符串中獲取在單詞 The 或 the 之后的所有 fat 和 mat 單詞。
(?<=(T|t)he\s)(fat|mat) => The fat cat sat on the mat.
從以上結(jié)果可以看到,The 和 the 是必須有的,但匹配的結(jié)果不會顯示它。
4.4 負(fù)向后行斷言
負(fù)向后行斷言是用于獲取不在特定模式之前的所有匹配的內(nèi)容。負(fù)向后行斷言表示為 (?<!...)。例如正則表達(dá)式 (?<!(T|t)he\s)(cat),表示:
在輸入字符中獲取所有不在 The 或 the 之后的所有單詞 cat。
(?<!(T|t)he\s)(cat) => The cat sat on cat.
從以上結(jié)果可以看到,The 和 the 是必須不能有的,但匹配的結(jié)果不會顯示它。
5. 標(biāo)記
標(biāo)記也稱為修飾符,因?yàn)樗鼤薷恼齽t表達(dá)式的輸出。這些標(biāo)志可以以任意順序或組合使用,并且是正則表達(dá)式的一部分。
| 標(biāo)記 | 描述 |
|---|---|
| i | 不區(qū)分大小寫: 將匹配設(shè)置為不區(qū)分大小寫。 |
| g | 全局搜索: 搜索整個(gè)輸入字符串中的所有匹配。 |
| m | 多行匹配: 會匹配輸入字符串每一行。 |
5.1 不區(qū)分大小寫
i 修飾符用于執(zhí)行不區(qū)分大小寫匹配。例如正則表達(dá)式 /The/gi,表示: 大寫字母 T,后跟小寫字母 h,后跟字母 e。
但是在正則匹配結(jié)束時(shí) i 標(biāo)記會告訴正則表達(dá)式引擎忽略這種情況。正如你所看到的,我們還使用了 g 標(biāo)記,因?yàn)槲覀円谡麄€(gè)輸入字符串中搜索匹配。
The => The fat cat sat on the mat.
/The/gi => The fat cat sat on the mat
5.2 全局搜索
g 修飾符用于執(zhí)行全局匹配 (會查找所有匹配,不會在查找到第一個(gè)匹配時(shí)就停止)。
例如正則表達(dá)式 /.(at)/g,表示: 除換行符之外的任意字符,后跟小寫字母 a,后跟小寫字母 t。因?yàn)槲覀冊谡齽t表達(dá)式的末尾使用了 g 標(biāo)記,它會從整個(gè)輸入字符串中找到每個(gè)匹配項(xiàng)。
.(at) => The fat cat sat on the mat.
/.(at)/g => The fat cat sat on the mat.
5.3 多行匹配
m 修飾符被用來執(zhí)行多行的匹配。正如我們前面討論過的 (^, $),使用定位符來檢查匹配字符是輸入字符串開始或者結(jié)束。但是我們希望每一行都使用定位符,所以我們就使用 m 修飾符。
例如正則表達(dá)式 /at(.)?$/gm,表示:
小寫字母 a,后跟小寫字母 t,匹配除了換行符以外任意字符零次或一次。而且因?yàn)?m 標(biāo)記,現(xiàn)在正則表達(dá)式引擎匹配字符串中每一行的末尾。
/.at(.)?$/"=> The fat
cat sat
on the mat.
/.at(.)?$/gm => The fat
cat sat
on the mat.
常用正則表達(dá)式
-
正整數(shù):
^\d+$ -
負(fù)整數(shù):
^-\d+$ -
電話號碼:
^+?[\d\s]{3,}$ -
電話代碼:
^+?[\d\s]+(?[\d\s]{10,}$ -
整數(shù):
^-?\d+$ -
用戶名:
^[\w\d_.]{4,16}$ -
字母數(shù)字字符:
^[a-zA-Z0-9]*$ -
帶空格的字母數(shù)字字符:
^[a-zA-Z0-9 ]*$ -
密碼:
^(?=^.{6,}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$ -
電子郵件:
^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$ -
IPv4 地址:
^((?:(?: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])*$ -
網(wǎng)址:
^(((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])$ -
萬事達(dá)信用卡號碼:
^(5[1-5][0-9]{14})*$