Regex,正則
在編寫處理字串的程式或⽹網頁時,經常會有尋找符合某些複雜規則的字串的需要。Regex 就是⽤用於描述這些規則的⼯工具。換句話說,Regex就是記錄⽂文本規則的代碼。
很可能你使⽤用過Windows/Dos下⽤用於⽂檔案尋找的萬用字元(wildcard),也就是*和 ?。如果你想尋找某個⽬目錄下的所有的Word⽂文檔的話,你會搜尋*.doc。在這⾥裡,*會被解釋成任意的字串。和萬用字元類似,Regex也是⽤用來進⾏行⽂文本匹配的⼯工具,只不過⽐比起萬用字元,它能更精確地描述你的需求——當然,代價就是更複雜——⽐比如你可以編寫⼀一個Regex,⽤用來尋找 所有以0開頭,後⾯面跟著2-3個數字,然後是⼀一個連字號“-”,最後是7或8位元字的字串 (像010-12345678或 0376-7654321)。
⽐比如him, history , high等等。⽤用hi來尋找的話,這⾥裡邊的hi 也會被找出來。如果要 精確地尋找hi這個單詞 的話,我們應該使⽤用\bhi\b。
\b是Regex規定的⼀一個特殊代碼(好吧,某些⼈人叫它元字元,metacharacter),代表著 單詞的開頭或結尾,也就是單詞的分界處 。雖然通常英⽂文的單詞是由空格,標點符號或者換⾏行來分隔的,但是\b並不匹配這些單詞分隔字元中的任何⼀一個,它只匹配⼀一個位置。
.是另⼀一個元字元,匹配 除了換⾏行符以外的任一字元 。*同樣是元字元,不過它代表的不是字元,也不是位置,⽽而是數量——它指定* 前邊的內容可以連續重複使⽤用任意次以使整個運算式得到匹配 。因此,.*連在⼀一起就意味著 任意數量的不包含換⾏行的字元 。
0\d\d-\d\d\d\d\d\d\d\d匹配這樣的字串: 以0開頭,然後是兩個數字,然後是⼀一個連字號“-”,最後是8個數字 (也就是中國的電話號碼。當然,這個例⼦子只能匹配區號為3位的情形)。
這⾥裡的 \d是個新的元字元,匹配 ⼀一位元字(0,或1,或2,或…⋯…⋯) 。-不是元字元,只匹配它本⾝身——連字號(或者減號,或者中橫線,或者隨你怎麼稱呼它)。
為了避免那麼多煩⼈人的重複,我們也可以這樣寫這個運算式:0\d{2}-\d{8}。這⾥裡\d後⾯面的{2}({8})的意思是前⾯面\d必須連續重複匹配2次(8次) 。
Regex⾥裡還有更多的元字元,⽐比如 \s匹配 任意的空⽩白符,包括空格,定位字元(Tab),換⾏行符,中⽂文全⾓角空格等 。\w匹配 字母或數字或底線或漢字等 。
\ba\w*\b匹配 以字母a開頭的單詞——先是某個單詞開始處(\b),然後是字母a,然後是任意數量的字母或數字(\w*),最後是單詞結束處(\b) 。\d+匹配 1個或更多連續的數字 。這⾥裡的 +是和 *類似的元字元,不同的是* 匹配 重複任意次(可能是0次) ,⽽而+ 則匹配 重複1次或更多次 。\b\w{6}\b匹配剛好6個字元的單詞。
元字元^(和數字6在同⼀一個鍵位上的符號)和$都匹配⼀一個位置,這和\b有點類似。^匹配你要⽤用來尋找的字串的開頭,$匹配結尾。這兩個代碼在驗證輸⼊入的內容時⾮非常有⽤用,⽐比如⼀一個⽹網站如果要求你填寫的QQ號必須為5位到12位元字時,可以使
⽤用: ^\d{5,12}$。
這⾥裡的{5,12}和前⾯面介紹過的{2}是類似的,只不過{2}匹配 只能不多不少重複2次 ,{5,12}則是 重複的次數不能少於5次,不能多於12次 ,否則都不匹配。因為使⽤用了^ 和$ ,所以輸⼊入的整個字串都要⽤用來和\d{5,12} 來匹配,也就是說整個輸⼊入 必須是5到12個數字 ,因此如果輸⼊入的QQ號能匹配這個Regex的話,那就符合要求了。
和忽略⼤大⼩小寫選項類似,有些Regex處理⼯工具還有⼀一個處理多⾏行的選項。如果選中了這個選項,^和 $的意義就變成了 匹配⾏行的開始處和結束處 。
如果你想尋找元字元本⾝身的話,⽐比如你尋找 . ,或者 * ,就出現了問題:你沒辦法指定它們,因為它們會被解釋成別的意思。這時你就得使⽤用\來取消這些字元的特殊意義。因此,你應該使⽤用\.和 \*。當然,要尋找 \ 本⾝身,你也得⽤用\\.
像[aeiou]就匹配 任何⼀一個英⽂文元⾳音字母 ,[.?!]匹配 標點符號(.或?或!) 。
我們也可以輕鬆地指定⼀一個字元範圍 ,像 [0-9]代表的含意與\d就是完全⼀一致的: ⼀一位元字 ;同理[a-z0-9A-Z_]也完全等同於\w(如果只考慮英⽂文的話)。
下⾯面是⼀一個更複雜的運算式:\(?0\d{2}[) -]?\d{8}。這個運算式可以匹配 ⼏幾種格式的電話號碼 ,像(010)88886666,或 022-22334455,或 02912345678等。我們對它進⾏行⼀一些分析吧:⾸首先是⼀一個逸出字元 \(,它能出現0次或1次(? ),然後是⼀一個0 ,後⾯面跟著2個數字(\d{2} ),然後是) 或- 或空格 中的⼀一個,它出現1次或不出現(? ),最後是8個數字(\d{8} )。
Regex⾥裡的分枝條件 指的是有⼏幾種規則,如果滿⾜足其中任意⼀一種規則都應該當成匹配,具體⽅方法是⽤用|把不同的規則分隔開。
例子:
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位)。原因是匹配分枝條件時,將會從左至右地測試每個條件,如果滿⾜足了某個分枝的話,就不會去再管其它的條件了。