正則之基本入門
來自: http://segmentfault.com/a/1190000004389850
以前看了許許多多的正則教程,收貨并不多,往往都是蜻蜓點水,一點就過。事實上,正則用處真的超級大,比如匹配innerHTML的內容,以及表單驗證,也是非他莫屬。這里,我結合js,對正則進行一個簡單的介紹吧。 如有紕漏歡迎指出,希望大家多多包涵。
js與正則的關系
在js中定義一個正則有兩種方法,一個是實例化,一個是字面量。分別看一下:
//實例化 var re = /\w+/; //這兩者等價 //字面量 var re = new RegExp('\\w+');
如果想添加一些flags也是沒有問題的。比較常用的flag有。/i,/g,/ig,/m.
/i (忽略大小寫,ignore) /g (全文查找出現的所有匹配字符,global) /m (多行查找,multiLine) /ig(全文查找、忽略大小寫,ignore+global)
所以, 使用flag之后可以這樣寫.
var reg = ^\d{5,12}\i$ ;//表示忽略大小寫,匹配; //或者 var reg = new RegExp(^\d{5,12}\i$);
正式入門正則
正則其實就是用來匹配字符串的。他用一個簡潔表達了,完成了你需要寫很多代碼的事,就和md(markdown)語法是一個道理。 用的人多了,自然成標準,這也是規則吧。
正則預定字符
預定字符,就是用程序比較難表達的一些字符,比如回車鍵,tab鍵(通過空格來區分達到的效果).常用的有:
字符 | 效果 |
---|---|
\t | 制表符,其實就是一個“Tab”鍵 |
\r | 回車符,如果你使用過word應該之后,在一個段落后面那個東西吧。 :) |
\n | 換行符,他和\r是有故事的,等下說,我們繼續 |
恩,大部分就是這幾個了。 上面提到 \r和\n,他們到底有什么卻別。 沒錯,看字面量,感覺return 不就是換行嗎? 其實,這樣說沒錯,但是得區分系統,在Unix為擴展的系統,在每行的結尾只有"\n",而在window下則是:"\n\r"(順序不能換). 所以,為了解決系統的差異,就出現了兩種: \r || \n.所以一般,我們匹配換行需要使用.\r||\n一起使用.
var reg = /[\r\n]/g;
這樣就能保證系統的兼容性.
字符類
所謂的字符類同樣也是將你平常要花很多時間做出來的,集成為一個簡潔表達。(相當于寫庫)。常用的字符類有如下幾個。
字符 | 效果 |
---|---|
. | 匹配換行符以外的任意字符 |
\d | 匹配所有數字 |
\D | 匹配非數字 |
\s | 匹配一個空格符 |
\S | 匹配非空格 |
\w | 匹配字母數字下劃線=>其實就是匹配單詞word(簡單易懂) |
\W | 匹配!字母數字下劃線=>就是不匹配單詞 |
來我們看幾個例子
console.log(/\s+/.test(" ")); //true console.log(/\d+/.test("1234231")); //true console.log(/\D+/.test(" ")); //true
其他的如上。
錨字符
這個應該算是正則里面,取名最好理解的一個。使用正則就是停船一樣,你需要設置你停的位置,我也需要設置我的邊界。常用的有一下幾個:
錨字符 | 效果 |
---|---|
^ | 匹配字符串的開頭,在多行檢索中,匹配一行的開頭 |
$ | 匹配字符串的結尾,在多行檢索中,匹配一行的結尾 |
\b | 匹配一個單詞的邊界 |
\B | 匹配非單詞邊界 |
這幾個應該算是我平常用的最多的幾個吧。如果你想匹配整個字符串,就可以組合使用"^ $";
var reg = /^\d+$/; //匹配整個字符串為數字
量詞字符
"望文生義",這類字符使用來限定某某出現的次數的。常用的有:
代碼 / 語法 | 說明 |
---|---|
* | 重復零次或更多次 |
+ | 重復一次或更多次 |
? | 重復零次或一次 |
{n} | 重復n次 |
{n,} | 重復n次或更多次 |
{n, m} | 重復n到m次 |
這個應該不用多說了。 直接看例子吧
console.log(/^\d+$/.test("123")); //true
上面說了這么多內置的字符,那我想使用特定字符類怎么辦嘞。其實也很簡單。使用"\"轉義字符。比如我想匹配大括號."{}".我可以這樣用:
console.log(/\{.+\}/.test("{123}")); //true
但事實上,量詞還分為3種,有貪婪量詞,惰性量詞,支配性量詞。
區分的依據是根據引擎的解析不同而形成。
貪婪量詞
這類量詞指的就是上文所說的: *,+,?。
他的匹配方法就是,全文匹配,如果不成功,則,將末尾的最后一個字符減去,再匹配,如果還不成功,則,再減一次。只到為0。 接著,往中間移動一位,再進行匹配,同樣的匹配模式。
</div>
console.log(/.+/.test("abcd")); //true
惰性量詞
使用方法: 基本量詞 ?
該量詞和貪婪量詞就像,一個是消極怠工,一個是積極工作。 惰性量詞一開始只會匹配一個字符,如果不成功,則在進行匹配。
</div>
console.log(/\d+?/.test("1fjkdf")); //true
這里闡述一些惰性和貪婪匹配的區別。
我們也通常把惰性稱為最少重復匹配。
舉個例子:
我們現在需要匹配blablablabla. 中的b~a間的詞。
使用貪婪匹配:
</div>
var str = "blablablabla"; console.log(str.match(/(b.*a)/g)); //["blablablabla"]
我們最少重復匹配(惰性匹配)
console.log(str.match(/(b.*?a)/g)); //["bla", "bla", "bla", "bla"]
支配性量詞
使用方法: 基本量詞 +;
該量詞就是只匹配一次,如果不符合則不匹配。
但是由于js不支持,所以,這里也不做過多的介紹。
</div>
正則: /\d*+/;
其實上面只要留個印象就可以,只有當你真正使用的時候,你才會有感觸。OK!!!基本內容說完了,現在輪到真正的進階,big boom~
中括號的用法
我們從小學學過來,老師告訴我們,我們使用括號有3種,一個是( ),一個是[],一個是{}.
而在正則里面,大括號已經被量詞字符給強占了,只剩下[]和(). 這里我們來說一下,中括號.
[],在正則里面代表的是一個單元字符,或者我寧愿叫他"或"括號. 因為他起到的主要作用就是,你可以匹配這個或者匹配那個或者...
吃個栗子:
var reg = /[abc]/; console.log(reg.test("a")); //true
可以看出,reg可以匹配 a|b|c. 平常使用的時候,可以直接向一個字符使用就可以了。
異或表達
這里會出現一個問題,比如,我不想匹配a,b,c中的任意一個該怎么辦呢? 其實,只需要在"[]"里面加上"^"即可。
</div>
console.log(/[^abc]/.test("c")); //false
范圍字符
范圍字符,就是可以省略一些周所周知的。 比如匹配26英文字母可以直接使用:a-z. 因為我們已經都知道了這個的意義。
其實,上面所說的字符類完全就可以使用中括號來代替。
</div>
\d => [0-9] \w => [0-9a-zA-Z_] \S => [^\t\n\x0B\f\r] (\f標識分頁符) ...
另外這個范圍字符還有一個好處,就是匹配中文。(電腦都是外國人發明的呀。)
console.log(/[\u4e00-\u9fa5]{1}/.test("艸")); //true
這就是中括號的常用用法。
小括號使用
小括號的主要作用其實就是分組。平常是用來提取匹配到的字符串。
分組使用
使用()對內容進行區分。
console.log(/(jimmy)+/.test("jimmy")); //true
而且,配合使用match方法,可以獲得匹配到的內容.
var name = "My name is Jimmy"; console.log(name.match(/(Jimmy)/g)); //["Jimmy"]
需要注意在括號里面寫正則和沒有括號的時候,是沒有區別的。我們可以在()內嵌套你想加的。(如果你想嵌套()的話,Sorry,這樣并沒有什么卵用).
var name = "My name is Jimmy Jimy"; console.log(name.match(/(Jimm?y)/g)); //["Jimmy", "Jimy"]
候選(或)
這個就相當于將括號加上一個或的功能. 即,在()里面使用"|"進行分隔。
</div>
var name = "My name is Jimmy sam"; var reg = /(jimmy|sam)+?/ig; console.log(name.match(reg)); //["jimmy","sam"]
反向引用
這個名字我真心不理解,什么"反向"... 我寧愿叫做,給分組加上標識符。這個的主要功能,就是給匹配到的小括號加上數字,來表明他是第幾個匹配到的。如果不加,則默認從左到右的順序為1,2,3...
</div>
var reg = /(100)\1/; var reg2 = /(100)(99)(101)\1\2\3/; //1=>100,2=>99,3=>101
在js中,通常是和replace搭配,才有威力。
var reg = /(100) (99)/; var str = "100 99"; console.log(str.replace(reg,"$2 $1")); //99 100
非捕獲分組
我們直接使用 "(...)"進行的匹配是捕獲分組。 我們來說一下什么叫 捕獲 . 上文中我們使用match進行正則匹配,而返回的數組中的元素就是通過正則捕獲的內容。 這就叫捕獲。
那這里的非捕獲,是什么意思呢? 其實很簡單,就是通過match不會匹配到內容。但還是可以起到分組的效果。
格式為: (?:xxx)
它最常用的地方就是匹配html.
var str=` <div class="pin"> <div class="box"> <img src="https://simg.open-open.com/show/d104cb79b036edf9ccaadc1d8de1766d.jpg" /> </div> </div>`; var reg = /<div(?:.|\r|\n)*div>/gi; console.log(str.match(reg));
大家可以去試一試,說到正則匹配,我還有一個想說的,就是上文所說的惰性匹配(最少重復)和貪婪匹配。
可以看到 “/< div(?:.|\r|\n)*div>/gi” 我這里使用的是貪婪匹配。他的結果是,盡量匹配到最外層的< /div>標簽。
即上面的結果為:
</div>
<div class="pin"> <div class="box"> <img src="https://simg.open-open.com/show/d104cb79b036edf9ccaadc1d8de1766d.jpg" /> </div> </div>
可以看出,貪婪匹配,對于兩個重復的/div 他會匹配到最外一層。
那我們使用惰性匹配試一試。
/< div(?:.|\r|\n)*?div>/gi
得到的結果為:
</div>
<div class="pin"> <div class="box"> <img src="https://simg.open-open.com/show/d104cb79b036edf9ccaadc1d8de1766d.jpg" /> </div>
可以看出少了一個< /div>,原因就是,惰性匹配盡量只會匹配到第一個重復的< /div>上面的。所以,總結一下,在使用正則匹配的時候需要搞清楚到底什么時候用惰性,什么時候用貪婪,這點很重要。 貪婪會匹配最外層,惰性會匹配最里層。
前瞻(零寬斷言)
前瞻分為正向前瞻和反向前瞻。(由于js只支持前瞻,所以后瞻只會提一下)。 他的作用就是,在匹配的字符后面,斷言說后面一定符合我的正則。 (好饒~~)算了,先說一下基本格式吧。
正則 | 名稱 | 作用 |
---|---|---|
(?=exp) | 正向前瞻 | 匹配exp前面的位置 |
(?!exp) | 反向前瞻 | 匹配后面不是exp的位置 |
(?<=exp) | 正向后瞻 | 匹配exp后面的位置 |
(?< !exp) | 反向后瞻 | 匹配后面不是exp的位置 |
看不懂了吧,我們來看一下詳細的內容。for instances:
var str = "happied boring"; var reg1 = /happ(?=ied)/g; var reg2 = /bor(?!ied)/; console.log(str.match(reg1)); //["happ"] console.log(str.match(reg2)); //["bor"]
從這個例子可以很容易看出前瞻后瞻到底是什么了。
回到上面的匹配html的例子。
這里我們有個需求,即只留下img標簽,那么就可以使用前瞻.
</div>
var str=` <div class="pin"> <div class="box"> <img src="https://simg.open-open.com/show/d104cb79b036edf9ccaadc1d8de1766d.jpg" /> </div> </div>`; var reg = /<(?!img)(?:.|\r|\n)*?>/gi; console.log(str.replace(reg,"")); //得到的結果為: <img src="https://simg.open-open.com/show/d104cb79b036edf9ccaadc1d8de1766d.jpg" />
另外,零寬斷言還有另外一個作用,即匹配以xxx為結尾的單詞。
這時候,你的leader對你有個要求,即,jimmy呀,你把ed結尾的單詞找出來哦。(好呀~)
這時候就可以使用前瞻了。
</div>
var str = "he is an interested person"; var reg = /\b\w+(?=ed\b)/ig; console.log(str.match(reg)); //["interest"]
結束語
關于正則的內容大概就是這些了。 其實正則的學習,不是只用看就能學會的,實踐才是硬道理。 通過,理論的學習,在加上踩過的坑,自然會對正則有著莫名的好感。 不過,大神就是大神,取名字就是這么別扭。 什么 零寬斷言,前瞻,后瞻,反向引用 blablabla... 在理解的同時可以根據自己的理解給這些名詞冠上自己的idea.我這里只是 正則的冰山一角,正則在任意一門語言內,用處都是超級大的。這里安利一個 總結的比較好的正則庫。 正則庫 . 還有一個在線的regExp測試工具. Debuggex
</div>