寫在開頭
在編碼過程中,正則表達(dá)式一直是經(jīng)常會(huì)出現(xiàn)但又困擾我們的知識(shí)點(diǎn),筆者就是每次遇到正則表達(dá)式就相當(dāng)頭痛,往往都是從網(wǎng)上復(fù)制一個(gè)表達(dá)式到代碼里草草了事。但其實(shí)如果不真正理解正則表達(dá)式的含義,我們就無法對(duì)其進(jìn)行修改來應(yīng)對(duì)特殊的需求。所以本文選取幾個(gè)常用的正則表達(dá)式進(jìn)行分析,旨在覆蓋基礎(chǔ)的正則表達(dá)式知識(shí),讓和我一樣的新手們不再懼怕那些看起來復(fù)雜的正則表達(dá)式。
定義
正則表達(dá)式是用于匹配字符串中字符組合的模式。
分析模式
首先我會(huì)把常用的正則表達(dá)式列出來,接著介紹與該表達(dá)式有關(guān)的知識(shí)點(diǎn),然后結(jié)合知識(shí)點(diǎn)并借用例子來逐步分析該正則表達(dá)式。最后我會(huì)列出一些匹配該正則表達(dá)式的例子。為了保證閱讀質(zhì)量,知識(shí)點(diǎn)分析不會(huì)一直重復(fù),到后來會(huì)只介紹重要或新出現(xiàn)的知識(shí)點(diǎn)。
相關(guān)連接
正式開始
用戶名:
^[a-z0-9_-]{3,16}$
- 知識(shí)點(diǎn):
-
^
:匹配輸入的開始 -
$
:匹配輸入的結(jié)束 -
{n,m}
:n和m都是正整數(shù)。匹配前面的字符至少n次,最多m次。如果n或者m的值為0,這個(gè)值被忽略。 -
[a-z]
:表示范圍a-z的一個(gè)字符集合,可以與該區(qū)間內(nèi)任何字符匹配。
-
- 從左到右逐步分析:
- 字符
^
開始匹配輸入 -
[a-zA-Z0-9_-]
表示該字符可以與a-z,A-Z,0-9,下劃線,破折號(hào)范圍內(nèi)的任意一個(gè)字符匹配 -
{3,16}
表示用戶名里有最少3個(gè)或者最多16個(gè)上述字符
- 字符
- 匹配舉例:
abcde
- 不匹配舉例:
-
ab
(太短)
-
手機(jī)號(hào):
/^1[3|4|5|7|8][0-9]{9}$/
//手機(jī)號(hào)的正則表達(dá)式通常被分為移動(dòng),聯(lián)通等幾種,因?yàn)楸疚淖⒅赜趯?duì)正則表達(dá)式的理解,所以不作分類,只對(duì)一個(gè)通用的表達(dá)式進(jìn)行分析。手機(jī)號(hào)的范圍以百度百科為準(zhǔn),即第一位是1開頭,第二位有3,4,5,7,8,第三位及之后的數(shù)字都是0-9的范圍
- 知識(shí)點(diǎn):
-
^
:匹配輸入的開始 -
$
:匹配輸入的結(jié)束 -
[a|b]
:表示匹配a或者b的一個(gè)字符集合 -
[0-9]
:表示范圍0-9的一個(gè)字符集合,可以與該區(qū)間內(nèi)任何字符匹配 -
{n}
:n是一個(gè)正整數(shù),匹配了前面一個(gè)字符剛好發(fā)生了n次
-
- 從左到右逐步分析:
- 字符
^
開始匹配輸入 - 1規(guī)定了必須第一位是1
-
[3|4|5|7|8]
表示第二位可以從3,4,5,7,8這幾個(gè)數(shù)字中任選其一 -
[0-9]{9}
表示匹配任意9個(gè)在0-9范圍內(nèi)的數(shù)字,同時(shí)也規(guī)定了必須有9個(gè)數(shù)
- 字符
- 匹配舉例:
13456789456
- 不匹配舉例
-
12345678987
(第二位不屬于3,4,5,7,8任何一個(gè)) -
138078787
(第三位開始少于9個(gè)數(shù))
-
郵箱:
/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
-
知識(shí)點(diǎn):
-
^
:匹配輸入的開始 -
$
:匹配輸入的結(jié)束 -
+
:匹配前面一個(gè)表達(dá)式一次或多次 -
\
:將其后的特殊字符,轉(zhuǎn)義為字面量 -
[a-z]
:表示范圍a-z的一個(gè)字符集合,可以與該區(qū)間內(nèi)任何字符匹配。
-
-
從左到右逐步分析(舉例:wys123@gmail.com):
- 字符
^
開始匹配輸入 -
[a-zA-Z0-9_-]
表示該字符可以與a-z,A-Z,0-9,下劃線,破折號(hào)范圍內(nèi)的任意一個(gè)字符匹配,緊跟著的加號(hào)表示可以匹配多個(gè)上述范圍內(nèi)的字符 (第2步代表wys123這個(gè)部分) -
@
規(guī)定了必須有@
符號(hào) - [a-zA-Z0-9_-]+ 的含義與第2步介紹的一樣 (代表gmail部分)
-
\.
將.
從特殊字符轉(zhuǎn)義為字面量,規(guī)定了必須有.
(gmail.com中的".") -
[a-zA-Z0-9_-]+
的含義還是與第2步中的一樣 (代表com部分)
- 字符
-
匹配舉例:
mario_a@qq.com
mario-a@qq.com
mario@a-b.c
-
不匹配舉例:
marioqq.com
mario@qqcom
mar&io@qq.com
十六進(jìn)制數(shù)字:
^#?([a-f0-9]{6}|[a-f0-9]{3})$
-
知識(shí)點(diǎn):
-
?
:匹配前面一個(gè)表達(dá)式0次或者1次 -
(x)
: 匹配x并記住該匹配項(xiàng),括號(hào)被稱為捕獲括號(hào) -
{n}
:n是一個(gè)正整數(shù),匹配了前面一個(gè)字符剛好發(fā)生了n次 -
a|b
:匹配a或者b
-
-
從左到右逐步分析:
- 因?yàn)?code>?的存在,所以
#
在這里是可有可無的 -
([a-f0-9]{6}|[a-f0-9]{3})
可以看成(A|B)
,其中A=[a-f0-9]{6}
,代表一個(gè)剛好存在6個(gè)范圍在af或者09的字符的集合;B=[a-f0-9]{3}
,代表一個(gè)剛好存在3個(gè)范圍在a-f或者0-9的集合。那么通俗講,不考慮#
,被匹配的字符集合長(zhǎng)度為3或者6,這3個(gè)或者6個(gè)字符必須都在范圍a-f或0-9內(nèi)。
- 因?yàn)?code>?的存在,所以
-
匹配舉例:
#000000
#ffffff
aff
-
不匹配舉例:
-
#00
(位數(shù)錯(cuò)誤,#后面不是3位或者6位) -
#-aaaaa
(范圍錯(cuò)誤,-不在范圍a-f或0-9內(nèi))
-
國(guó)內(nèi)電話號(hào)碼(帶區(qū)號(hào)):
^\d{3}-\d{8}|\d{4}-\d{7,8}$
-
知識(shí)點(diǎn):
-
\d
:匹配一個(gè)數(shù)字 -
{n}
:n是一個(gè)正整數(shù),匹配了前面一個(gè)字符剛好發(fā)生了n次 -
{n,m}
:n和m都是正整數(shù)。匹配前面的字符至少n次,最多m次。如果n活著m的值為0,這個(gè)值被忽略。
-
分析:
這個(gè)例子與16進(jìn)制的例子很像,可以將其看成X|Y
,其中X=\d{3}-\d{8}
,代表3個(gè)數(shù)字+一個(gè)-
+8個(gè)數(shù)字;Y=\d{4}-\d{7,8}
,代表4個(gè)數(shù)字+一個(gè)-
+7或8個(gè)數(shù)字,所以該正則表達(dá)式匹配了兩種電話號(hào)碼的模式-
匹配舉例:
021-86279200
0574- 86279200
-
不匹配舉例:
-
021-86278
(不匹配,位數(shù)不夠) -
86279200
(不匹配,雖然有時(shí)候也會(huì)需要匹配這一類不帶區(qū)號(hào)的電話號(hào)碼,但在本文采用的表達(dá)式中強(qiáng)制要求加上區(qū)號(hào),所以這個(gè)例子也不匹配)
-
URL:
^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
-
知識(shí)點(diǎn):
-
\
:可以將其后的特殊字符,轉(zhuǎn)義為字面量 -
?
: 匹配前一個(gè)表達(dá)式0次或1次 -
\w
:匹配一個(gè)單字字符(字母、數(shù)字或下劃線),等價(jià)于[A-Za-z0-9_] -
*
: 匹配前一個(gè)表達(dá)式0次或多次
-
-
分析:
這個(gè)表達(dá)式相對(duì)前面幾個(gè)較復(fù)雜,我們先把它分塊來看:
URL分析- 紅色部分:s后面的問號(hào)代表可以匹配http或者h(yuǎn)ttps,
\
將/
轉(zhuǎn)義成了字面量,所以連在一起就是http://
或者https://
,然后紅色部分最后的問號(hào)代表https://
或者http://
可以都不要,直接寫url比如www.baidu.com
,這也是可以被匹配的 - 橙色部分:
[\da-z\.-]
代表了表示了范圍為數(shù)字,小寫字母,點(diǎn)或者-
的字符集合,后面的加號(hào)表示可以匹配多個(gè)上述范圍內(nèi)的字符 - 綠色部分:
\
將.
轉(zhuǎn)義成了字面量,這里表示必須要有一個(gè).
字符 - 藍(lán)色部分:
[a-z\.]
代表了范圍為小寫字母或者點(diǎn)的字符集合,{2,6}表示可以有最少2個(gè),最多6個(gè)上述范圍的字符。橙色,綠色和藍(lán)色部分組成了域名 - 粉色部分:
[\/\w\.-]
表示了范圍為/
,字母,數(shù)字,下劃線,點(diǎn)或者"-"的字符集合,后面的*
表示可以匹配這個(gè)式子0次或者多次。其實(shí)筆者在這里對(duì)為什么要有兩個(gè)*
字符表示疑問,我認(rèn)為這兩個(gè)*
號(hào)作用相同,取其一即可,粉色部分是路徑和文件名 - 綠色部分:
\
將/
轉(zhuǎn)義成字面量后,跟隨的?
代表該/
可有可無,換句話說,www.baidu.com/something
和www.baidu.com/something/
都可以被匹配。
- 紅色部分:s后面的問號(hào)代表可以匹配http或者h(yuǎn)ttps,
-
匹配舉例:
https://www.google.co.uk/
https://zh.wikipedia.org/wiki/
-
不匹配舉例:
-
htts://www.baidu.com
(http要么不存在要么整個(gè)存在,這里不符合)
-
匹配首尾空白字符(可用來刪除首尾空白字符)
^\s*|\s*$
- 知識(shí)點(diǎn):
-
\s
:匹配一個(gè)空白字符,包括空格、制表符、換頁(yè)符合換行符 -
^
:匹配輸入的開始 -
$
:匹配輸入的結(jié)束 - 注意
\s
和\S
是相反的意思,不要混淆大小寫
-
- 分析:
- 其實(shí)往往越簡(jiǎn)單的表達(dá)式越難理解,對(duì)于這個(gè)表達(dá)式我決定用多個(gè)例子一步步解析。首先我們先詳細(xì)測(cè)試一下表達(dá)式
^a|b$
所能匹配的字符串,在字符串"aabb"中,其匹配了第一個(gè)a和第二個(gè)b,換句話說,匹配了首尾的a和b。再來看一看^a*|b*
,這次用字符串aacaabbcbb
來測(cè)試,可以看到匹配了首尾的"aa"和"bb",但并沒有匹配兩個(gè)c之間的aabb
,這是因?yàn)?code>^和$
存在的緣故,實(shí)際上它會(huì)匹配開始后和結(jié)束前的a*
或b*
字符串. 那么現(xiàn)在我們重新來看上述的表達(dá)式,將a
和b
都替換為\s*
后,該式子匹配的是字符串首尾的連續(xù)空白字符,這里有兩個(gè)關(guān)鍵詞:首尾和連續(xù)。之所以只匹配首尾,是因?yàn)樽址涫资瞧ヅ溟_始后最先被判斷的,而字符串句尾是匹配結(jié)束前最后被判斷的,所以符合了符號(hào)^
和$
所代表的意思,至于連續(xù),則是由*
所決定的,如果不帶*
,那么只會(huì)匹配首尾的一個(gè)空白字符。
- 其實(shí)往往越簡(jiǎn)單的表達(dá)式越難理解,對(duì)于這個(gè)表達(dá)式我決定用多個(gè)例子一步步解析。首先我們先詳細(xì)測(cè)試一下表達(dá)式
- 匹配舉例:
-
aacaab bcbb
(只匹配首尾空格,中間的空格不匹配)
-
- 不匹配舉例:
-
a b c
(只匹配首尾空格,中間的空格不匹配)
-
未涉及到的常用特殊字符(摘自MDN)
-
(?:x)
:匹配 'x' 但是不記住匹配項(xiàng)。這種叫作非捕獲括號(hào),使得你能夠定義為與正則表達(dá)式運(yùn)算符一起使用的子表達(dá)式。來看示例表達(dá)式 /(?:foo){1,2}/。如果表達(dá)式是 /foo{1,2}/,{1,2}將只對(duì) ‘foo’ 的最后一個(gè)字符 ’o‘ 生效。如果使用非捕獲括號(hào),則{1,2}會(huì)匹配整個(gè) ‘foo’ 單詞。 -
x(?=y)
:匹配'x'僅僅當(dāng)'x'后面跟著'y'.這種叫做正向肯定查找。
例如,/Jack(?=Sprat)/會(huì)匹配到'Jack'僅僅當(dāng)它后面跟著'Sprat'。/Jack(?=Sprat|Frost)/匹配‘Jack’僅僅當(dāng)它后面跟著'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配結(jié)果的一部分。 -
[^xyz]
:一個(gè)反向字符集。也就是說, 它匹配任何沒有包含在方括號(hào)中的字符。你可以使用破折號(hào)(-)來指定一個(gè)字符范圍。任何普通字符在這里都是起作用的。例如,[^abc] 和 [^a-c] 是一樣的。他們匹配"brisket"中得‘r’,也匹配“chop”中的‘h’。
總結(jié)
至此,借用一些常見的正則表達(dá)式,已經(jīng)把MDN里提到的大部分特殊字符都分析了一遍,筆者本人也是一個(gè)新手,雖然花了很多功夫試圖透徹理解上述各個(gè)表達(dá)式的含義,但文章中肯定還存在理解有偏差的地方,歡迎指正。