正則表達式快速入門
元字符:
/b 代表着單詞的開頭或結尾,也就是單詞的分界處.如果要精確地查找hi這個單詞的話,我們應該使用/bhi/b.
.是另一個元字符,匹配除了換行符以外的任意字符,*同樣是元字符,它指定*前邊的內容可以重複任意次以使整個表達式得到匹配。
.*連在一起就意味着任意數量的不包含換行的字符。
/d是一個新的元字符,匹配任意的數字,0/d/d-/d/d/d/d/d/d/d/d也就是中國的電話號碼.爲了避免那麼多煩人的重複,我們也可以這樣寫這個表達式:0/d{2}-/d{8}。
/s匹配任意的空白符,包括空格,製表符(Tab),換行符,中文全角空格等。/w匹配字母或數字或下劃線或漢字。
/b/w{6}/b 匹配剛好6個字母/數字的單詞。
字符轉義:使用/來取消這些字符的特殊意義。因此,你應該使用/.和/*。當然,要查找/本身,你也得用//。
代碼 說明
. 匹配除換行符以外的任意字符
/w 匹配字母或數字或下劃線或漢字
/s 匹配任意的空白符
/d 匹配數字
/b 匹配單詞的開始或結束
^ 匹配字符串的開始
$ 匹配字符串的結束
重複:
常用的限定符
代碼/語法 說明
* 重複零次或更多次
+ 重複一次或更多次
? 重複零次或一次
{n} 重複n次
{n,} 重複n次或更多次
{n,m} 重複n到m次
要想查找數字,字母或數字,你只需要在中括號裏列出它們就行了,像[aeiou]就匹配任何一個元音字母,[.?!]匹配標點符號(.或?或!)
反義:
常用的反義代碼
代碼/語法 說明
/W 匹配任意不是字母,數字,下劃線,漢字的字符
/S 匹配任意不是空白符的字符
/D 匹配任意非數字的字符
/B 匹配不是單詞開頭或結束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou這幾個字母以外的任意字符
替換:
正則表達式裏的替換指的是有幾種規則,如果滿足其中任意一種規則都應該當成匹配,具體方法是用|把不同的規則分隔開。
0/d{2}-/d{8}|0/d{3}-/d{7}這個表達式能匹配兩種以連字號分隔的電話號碼:一種是三位區號,8位本地號(如010-12345678),一種是4位區號,7位本地號(0376-2233445)。
/ (0/d{2}/)[- ]?/d{8}|0/d{2}[- ]?/d{8}這個表達式匹配3位區號的電話號碼,其中區號可以用小括號括起來,也可以不用,區號與本地號間可以用連字號或空格間隔,也可以沒有間隔。你可以試試用替換|把這個表達式擴展成也支持4位區號的。
/d{5}-/d{4} |/d{5}這個表達式用於匹配美國的郵政編碼。美國郵編的規則是5位數字,或者用連字號間隔的9位數字。之所以要給出這個例子是因爲它能說明一個問題:使用替換時,順序是很重要的。如果你把它改成/d{5}|/d{5}-/d{4}的話,那麼就只會匹配5位的郵編(以及9位郵編的前5位)。原因是匹配替換時,將會從左到右地測試每個分枝條件,如果滿足了某個分枝的話,就不會去管其它的替換條件了。
分組:
如果想要重複一個字符串又該怎麼辦?你可以用小括號來指定子表達式(也叫做分組),然後你就可以指定這個子表達式的重複次數了。
(/d{1,3}/.){3}/d{1,3}是一個簡單的IP地址匹配表達式。要理解這個表達式,請按下列順序分析它:/d{1,3}匹配1到3位的數字,(/d{1,3}/.}{3}匹配三位數字加上一個英文句號(這個整體也就是這個分組)重複3次,最後再加上一個一到三位的數字(/d{1,3})。不幸的是,它也將匹配256.300.888.999這種不可能存在的IP地址(IP地址中每個數字都不能大於255)。如果能使用算術比較的話,或許能簡單地解決這個問題,但是正則表達式中並不提供關於數學的任何功能,所以只能使用冗長的分組,選擇,字符類來描述一個正確的IP地址:((2[0-4] /d|25[0-5]|[01]?/d/d?)/.){3}(2[0-4]/d|25[0-5]|[01]?/d/d?)。
後向引用:
後向引用用於重複搜索前面某個分組匹配的文本。例如,/1代表分組1匹配的文本。難以理解?請看示例:
/b(/w+)/b/s+/1/b可以用來匹配重複的單詞,像go go, kitty kitty。首先是一個單詞,也就是單詞開始處和結束處之間的多於一個的字母或數字(/b(/w+)/b),然後是1個或幾個空白符(/s+,最後是前面匹配的那個單詞(/1)。
懶惰限定符
*? 重複任意次,但儘可能少重複
+? 重複1次或更多次,但儘可能少重複
?? 重複0次或1次,但儘可能少重複
{n,m}? 重複n到m次,但儘可能少重複
{n,}? 重複n次以上,但儘可能少重複
位置指定:
接下來的四個用於查找在某些內容(但並不包括這些內容)之前或之後的東西,也就是說它們用於指定一個位置,就像/b,^,$那樣,因此它們也被稱爲零寬斷言。最好還是拿例子來說明吧:
(? =exp)也叫零寬先行斷言,它匹配文本中的某些位置,這些位置的後面能匹配給定的後綴exp。比如/b/w+(?=ing/b),匹配以 ing結尾的單詞的前面部分(除了ing以外的部分),如果在查找I'm singing while you're dancing.時,它會匹配sing和 danc。
(?<=exp)也叫零寬後行斷言,它匹配文本中的某些位置,這些位置的前面能給定的前綴匹配exp。比如(?<=/bre)/w+/b會匹配以re開頭的單詞的後半部分(除了re以外的部分),例如在查找reading a book時,它匹配ading。
假如你想要給一個很長的數字中每三位間加一個逗號(當然是從右邊加起了),你可以這樣查找需要在前面和裏面添加逗號的部分:((?<=/d)/d{3})*/b。請仔細分析這個表達式,它可能不像你第一眼看出來的那麼簡單。
下面這個例子同時使用了前綴和後綴:(?<=/s)/d+(?=/s)匹配以空白符間隔的數字(再次強調,不包括這些空白符)。
負向位置指定:
前面我們提到過怎麼查找不是某個字符或不在某個字符類裏的字符的方法(反義)。但是如果我們只是想要確保某個字符沒有出現,但並不想去匹配它時怎麼辦?例如,如果我們想查找這樣的單詞--它裏面出現了字母q,但是q後面跟的不是字母u,我們可以嘗試這樣:
/b/w*q [^u]/w*/b匹配包含後面不是字母u的字母q的單詞。但是如果多做測試(或者你思維足夠敏銳,直接就觀察出來了),你會發現,如果q出現在單詞的結尾的話,像Iraq,Benq,這個表達式就會出錯。這是因爲[^u]總是匹配一個字符,所以如果q是單詞的最後一個字符的話,後面的 [^u]將會匹配 q後面的單詞分隔符(可能是空格,或者是句號或其它的什麼),後面的/w+/b將會匹配下一個單詞,於是/b/w*q[^u]/w*/b 就能匹配整個 Iraq fighting。負向位置指定能解決這樣的問題,因爲它只匹配一個位置,並不消費任何字符。現在,我們可以這樣來解決這個問題:/b/w*q (?!u) /w*/b。
零寬負向先行斷言(?!exp),只會匹配後綴exp不存在的位置。/d{3}(?!/d)匹配三位數字,而且這三位數字的後面不能是數字。
同理,我們可以用(?<!exp),零寬負向後行斷言來查找前綴exp不存在的位置:(?<![a-z])/d{7}匹配前面不是小寫字母的七位數字(實驗時發現錯誤?注意你的“區分大小寫”先項是否選中)。
一個更復雜的例子:(?<=<(/w+)>).*(?=<///1>)匹配不包含屬性的簡單HTML標籤內裏的內容。 (<?(/w+)>)指定了這樣的前綴:被尖括號括起來的單詞(比如可能是<b>),然後是.*(任意的字符串),最後是一個後綴(?=<///1>)。注意後綴裏的//,它用到了前面提過的字符轉義;/1則是一個反向引用,引用的正是捕獲的第一組,前面的(/w +)匹配的內容,這樣如果前綴實際上是<b>的話,後綴就是</b>了。整個表達式匹配的是<b>和< /b>之間的內容(再次提醒,不包括前綴和後綴本身)。
註釋:
小括號的另一種用途是能過語法(?#comment)來包含註釋。例如:2[0-4]/d(?#200-249)|25[0-5](?#250-255)|[01]?/d/d?(?#0-199)。
要包含註釋的話,最好是啓用“忽略模式裏的空白符”選項,這樣在編寫表達式時能任意的添加空格,Tab,換行,而實際使用時這些都將被忽略。啓用這個選項後,在#後面到這一行結束的所有文本都將被當成註釋忽略掉。
例如,我們可以前面的一個表達式寫成這樣:
(?<= # 查找前綴,但不包含它
<(/w+)> # 查找尖括號括起來的字母或數字(標籤)
) # 前綴結束
.* # 匹配任意文本
(?= # 查找後綴,但不包含它
<///1> # 查找尖括號括起來的內容:前面是一個"/",後面是先前捕獲的標籤
) # 後綴結束
貪婪與懶惰:
當正則表達式中包含能接受重複的限定符(指定數量的代碼,例如*, {5,12}等)時,通常的行爲是(在使整個表達式能得到匹配的前提下)匹配儘可能多的字符。考慮這個表達式:a.*b,它將會匹配最長的以a開始,以b 結束的字符串。如果用它來搜索aabab的話,它會匹配整個字符串aabab。這被稱爲貪婪匹配。
有時,我們更需要懶惰匹配,也就是匹配儘可能少的字符。前面給出的限定符都可以被轉化爲懶惰匹配模式,只要在它後面加上一個問號?。這樣.*?就意味着匹配任意數量的重複,但是在能使整個匹配成功的前提下使用最少的重複。現在看看懶惰版的例子吧:
a.*?b匹配最短的,以a開始,以b結束的字符串。如果把它應用於aabab的話,它會匹配aab和ab(爲什麼第一個匹配是aab而不是ab?簡單地說,最先開始的區配最有最大的優先權??The Match That Begins Earliest Wins)。
表5.懶惰限定符 *? 重複任意次,但儘可能少重複
+? 重複1次或更多次,但儘可能少重複
?? 重複0次或1次,但儘可能少重複
{n,m}? 重複n到m次,但儘可能少重複
{n,}? 重複n次以上,但儘可能少重複
-------------------------------------------------------
下面是一些常用的正則表達式:
匹配中文字符的正則表達式: [/u4e00-/u9fa5]
評註:匹配中文還真是個頭疼的事,有了這個表達式就好辦了
匹配雙字節字符(包括漢字在內):[^/x00-/xff]
評註:可以用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1)
匹配空白行的正則表達式:/n/s*/r
評註:可以用來刪除空白行
匹配HTML標記的正則表達式:<(/S*?)[^>]*>.*?<//1>|<.*? />
評註:網上流傳的版本太糟糕,上面這個也僅僅能匹配部分,對於複雜的嵌套標記依舊無能爲力
匹配首尾空白字符的正則表達式:^/s*|/s*$
評註:可以用來刪除行首行尾的空白字符(包括空格、製表符、換頁符等等),非常有用的表達式
匹配Email地址的正則表達式:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
評註:表單驗證時很實用
匹配網址URL的正則表達式:[a-zA-z]+://[^/s]*
評註:網上流傳的版本功能很有限,上面這個基本可以滿足需求
匹配帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
評註:表單驗證時很實用
匹配國內電話號碼:/d{3}-/d{8}|/d{4}-/d{7}
評註:匹配形式如 0511-4405222 或 021-87888822
匹配騰訊QQ號:[1-9][0-9]{4,}
評註:騰訊QQ號從10000開始
匹配中國郵政編碼:[1-9]/d{5}(?!/d)
評註:中國郵政編碼爲6位數字
匹配身份證:/d{15}|/d{18}
評註:中國的身份證爲15位或18位
匹配ip地址:/d+/./d+/./d+/./d+
評註:提取ip地址時有用
匹配特定數字:
^[1-9]/d*$ //匹配正整數
^-[1-9]/d*$ //匹配負整數
^-?[1-9]/d*$ //匹配整數
^[1-9]/d*|0$ //匹配非負整數(正整數 + 0)
^-[1-9]/d*|0$ //匹配非正整數(負整數 + 0)
^[1-9]/d*/./d*|0/./d*[1-9]/d*$ //匹配正浮點數
^-([1-9]/d*/./d*|0/./d*[1-9]/d*)$ //匹配負浮點數
^-?([1-9]/d*/./d*|0/./d*[1-9]/d*|0?/.0+|0)$ //匹配浮點數
^[1-9]/d*/./d*|0/./d*[1-9]/d*|0?/.0+|0$ //匹配非負浮點數(正浮點數 + 0)
^(-([1-9]/d*/./d*|0/./d*[1-9]/d*))|0?/.0+|0$ //匹配非正浮點數(負浮點數 + 0)
評註:處理大量數據時有用,具體應用時注意修正
匹配特定字符串:
^[A-Za-z]+$ //匹配由26個英文字母組成的字符串
^[A-Z]+$ //匹配由26個英文字母的大寫組成的字符串
^[a-z]+$ //匹配由26個英文字母的小寫組成的字符串
^[A-Za-z0-9]+$ //匹配由數字和26個英文字母組成的字符串
^/w+$ //匹配由數字、26個英文字母或者下劃線組成的字符串