在javascript編程中,會時常用到正則表達(dá)式。因此,決定對正則表達(dá)式進(jìn)行學(xué)習(xí)。
學(xué)習(xí)的目的主要是能夠在編程中使用到它,因此,不要求精通,只需對其基本知識有所了解即可。學(xué)習(xí)材料主要來自正則表達(dá)式30分鐘入門教程,作者deerchao。
從目錄及速覽全文后,我認(rèn)為,對正則表達(dá)式的基本了解應(yīng)該主要從字符、限定符、規(guī)則、語法這四方面進(jìn)行歸納。通過限定符和元字符配合使用來確定匹配字符的次數(shù),通過設(shè)定并遵守一些規(guī)則來達(dá)到更多的匹配方式,最后進(jìn)階使用語法來達(dá)到最高層的正則表達(dá)式匹配。
1.字符:正則表達(dá)式中的字符分為原意文本字符和元字符。確定的英文字母和數(shù)字在正則表達(dá)式中可以用其本身表示(愿意文本字符),而元字符是一些具有特殊意義的正則表達(dá)式特殊代碼,常用的元字符有下:
- . 匹配除換行符以外的任意字符;
- \w 匹配字母或數(shù)字或下劃線或漢字;
- \s 匹配任意的空白符;
- \d 匹配數(shù)字;
- \b 匹配字符串開始或結(jié)束;
- ^ 匹配字符串開始;
- $ 匹配字符串的結(jié)束;
舉個例子,\b\d6\d\b表示的是匹配首字符為任意數(shù)字、中間字符為6、尾字符為任意數(shù)字的一個字符串,而\d6\d$同樣也是匹配的這樣一個字符串。由元字符會衍生出一個問題:元字符中有一些如.等是用特殊符號來表示的,那么在正則表達(dá)式中用什么來匹配它們自己呢?這就引出了轉(zhuǎn)義的規(guī)則:在這些特殊符號前面使用“\”對其進(jìn)行轉(zhuǎn)義,就可以匹配它們自身了。那么“\”又用什么來匹配呢?還是用它自己進(jìn)行轉(zhuǎn)義:正則表達(dá)式中的“\”就是用來匹配“\”的。
2.限定符:有了字符并不能解決問題,比如,如果想要匹配一個12位長的任意數(shù)字,難道要使用“\d”12次,那位數(shù)再多一些怎么辦呢?
于是限定符就起作用了。我的理解,限定符就是規(guī)定正則表達(dá)式中一個字符或一段字符要匹配的次數(shù),如下,是一些常用的限定符:
- * 重復(fù)零次或更多次;
- + 重復(fù)一次或更多次;
- ? 重復(fù)零次或一次;
- {n,} 重復(fù)n次或更多次;
- {n,m} 重復(fù)n到m次;
- {n} 重復(fù)n次;
- *? 重復(fù)任意次,但盡可能少重復(fù);
- +? 重復(fù)1次或更多次,但盡可能少重復(fù);
- ?? 重復(fù)0次或1次,但盡可能少重復(fù);
- {n,m}? 重復(fù)n到m次,但盡可能少重復(fù);
- {n,}? 重復(fù)n次以上,但盡可能少重復(fù);
于是,要匹配12位長的數(shù)字,只需“\d{12}”這樣寫就行了。從上面可以明顯的看出,前五個和后五個以中間第六個為界限,可以歸納為兩大類,前五個叫做貪婪匹配,后五個叫做懶惰匹配(為什么用兩個貶義詞來定義,一臉懵逼??)。
3.規(guī)則:有了字符和限定符還并不能解決問題,還缺少一些規(guī)則,這些規(guī)則使我們能夠更便捷的使用正則表達(dá)式。比較常用的規(guī)則有:字符類、反義、分支條件、分組、和向后引用。以下一一解釋:
字符類:如果只想匹配某幾個確定的字母或數(shù)字,就需要使用到字符類。舉個例子,如果我只想匹配一段字符串中是否有a、b、c這三個字母,那么只需“[abc]”這樣表示就可以進(jìn)行匹配了,而這正是一個字符類。
反義:有時候,我們需要的結(jié)果是不想字符串中有某個字符或是某段字符(既匹配不含這些字符的字符串),就需要用到反義規(guī)則了,常見的反義規(guī)則代碼有下:
- \W 匹配任意不是字母,數(shù)字,下劃線,漢字的字符;
- \S 匹配任意不是空白符的字符;
- \D 匹配任意非數(shù)字的字符;
- \B 匹配不是單詞開頭或結(jié)束的位置;
- [^x] 匹配除了x以外的任意字符;
- [^aeiou] 匹配除了aeiou這幾個字母以外的任意字符;
分支條件:指的是有幾種匹配方式,如果滿足其中任意一種匹配方式都應(yīng)該當(dāng)成匹配。而分支條件的具體方法是把不同的匹配方式用|隔開。舉個例子,0\d{2}-\d{8}|0\d{3}-\d{7}這個正則表達(dá)式指的是只要某段字符串能夠滿足0xx-xxxxxxxx或者0xxx-xxxxxxx兩種形式中的任意一種(x代表數(shù)字),就可以被匹配。而分支條件需要遵守另外一條規(guī)則:正則表達(dá)式的匹配都是從左到右進(jìn)行匹配,如果字符串滿足了前面的匹配方式,就被前面匹配了,既使它(或者它內(nèi)部某段字符串,亦或它加上前后某段字符串)能夠滿足后面的匹配方式,也不會再次被后面匹配。
分組:分組的規(guī)則主要是為了滿足一些語法或是規(guī)則,具體方法是使用小括號將某段正則表達(dá)式包圍起來,既對其進(jìn)行了分組,在默認(rèn)情況下,如果一段正則表達(dá)式中有幾個組,那么他們的組號是從左至右從1開始依次增大的。\b(\w+)\d(\w+)\b這段正則表達(dá)式里,第一個(\w+)的組號為1,第二個(\w+)的組號為2。
而依賴分組規(guī)則,后向引用就起到了很大的作用。如:有這樣一段表達(dá)式,\b(\w+)\b\s+(\w+)\b,從中可見,第一個括號的內(nèi)容與第二個完全相同,此時,完全可以利用后項引用規(guī)則,用第一個組的組號來替代第二個組:\b(\w+)\b\s+\1\b。需要注意的是,利用組號來引用,一定要加上轉(zhuǎn)義符,如“\1”。
4.語法:常用的語法也主要依賴于分組,如下:
- (exp) 匹配exp,并捕獲文本到自動命名的組里;
- (?<name>exp) 匹配exp,并捕獲文本到名稱為name的組里,也可以寫成(?'name'exp);
- (?:exp) 匹配exp,不捕獲匹配的文本,也不給此分組分配組號;
- (?=exp) 匹配exp前面的位置;
- (?<=exp) 匹配exp后面的位置;
- (?!exp) 匹配后面跟的不是exp的位置;
- (?<!exp) 匹配前面不是exp的位置;
- (?#comment) 這種類型的分組不對正則表達(dá)式的處理產(chǎn)生任何影響,用于提供注釋讓人閱讀;
以上,前三個屬于捕獲,其后四個屬于零寬斷言,最后一個是注釋。需要注意的是零寬斷言,為什么叫零寬?因為它匹配的是一個位置,并不是字符;而斷言指的是這個位置需要滿足一定的條件。
以上就是正則表達(dá)式的大半基礎(chǔ)知識了,除此之外,還有處理選項、平衡組(遞歸匹配)等需要了解。對于一些常規(guī)的js編程如表單驗證等,利用上面的知識就足夠了。
但是,只利用正則表達(dá)式來匹配字符串并不能完全解決問題,比如有時需要計算字符串的字節(jié)長度,而字符串中含有漢字的情況下,需要將漢字進(jìn)行轉(zhuǎn)碼,形成unicode編碼,再對編碼用“\”來轉(zhuǎn)義,才能正確匹配找到漢字,并計算字節(jié)數(shù)。