javascript中正則表示式語法詳解
好久都沒有寫部落格了,主要是太懶了,尤其是在陽春三月,風和日麗的日子,太陽暖暖的照在身上,真想美美的睡上一覺。就導致了這篇部落格拖到現在才開始動筆,javascript的正則這一塊也不是什麼新的東西,主要是以前本人一遇到寫正則的需求就開始頭大,頭疼,網上剽竊,東拼西湊,反正就是各種不適應,所以我打算系統的把正則表示式看一遍,一來是自己有所提升,這一塊知識點的查漏補缺,二來是給大家分享一下。好了,下面我們直接進入主題:
正則是匹配字串特定模式的一種表示式,官方是這樣說的,但我的理解不外乎就是匹配字元竄嘛,舉個例子大家就明白了。比如我們要驗證郵箱,試想一下如果我們不用正則來匹配,直接用程式碼,迴圈,判斷各種搗鼓來驗證還真是一件非常麻煩的事情。如果用正則怎麼來做了,這裡為了照顧小白(當然我也是重小白走來的,所以小白很單純,小白很善良,小白很偉大)我就寫偽正則來描述: 所有0-9或者a-z或者A-Z的字元出現一次到多次 加上(就是前面出現了的所有0-9...的字元跟上) "."或者"_"出現0次或者1次,然後在跟上 "@"符號 跟上 xxx.xx這種格式。 不知道我這樣來描述各位親有沒有明白一點,不明白也不要緊,這裡我只是隨便舉個列子,提一下,在下文的某個位置我會專門一步一步分析幾個非常複雜的正則表達讓大家能夠很快的明白正則的語義。
上面舉了一個郵箱地址的正則表示式,比如這一竄 /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/
;要看懂坑爹的這一竄,還得從基礎一步一步的來。首先給大家介紹javascript經常使用正則的物件和方法:
RegExp 這個是正則物件, 比如匹配字串"1234"中的"23"可以這樣玩: (new RegExp("23")).test("1234"); //out true;
當然正則物件還有一種寫法:
var reg = /23/; reg.test("1234") //out true; RegExp.test(String) ; //這個方法上面的用上了,匹配字串是否為指定格式 RegExp.exec(String); //返回查詢的值 var str = "123 aa cat Cat caT"; var reg = /cat/i; reg.exec(str); // out "cat" 如果有則返回,沒有的話就返回null String.search(RegExp) ; // 返回索引位置,類似indexOf() var data = "123123,213,12312,312,3,Cat,cat,dsfsdfs,"; var reCat = /cat/gi; alert(data.search(reCat)); //out "23" String.replace(RegExp,String); // 將字串替換成另外一個字元竄,RegExp指定的格式,String要替換的字串 var str = "1234aa67aa89"; var reg = /aa/gi; str.replace(reg,"") ; //out "12346789" String.split(RegExp) ; // 將字串拆分成陣列 var str = "1234aa67aa89"; var reg = /aa/gi; str.split(reg) ; //out [1234,67,89] String.match(RegExp); //將指定格式的字串以陣列的方式返回 var data = "123123,"; var reCat = /cat/gi; var arrMactches = data.match(reCat); // out ["Cat","cat"]
上面的的方法是在字串過濾操作中經常用到的方法, 當然還有一些我沒有全部列舉出來,用到了在去差API也不遲,好了我們熟悉了操作正則的這些方法之後我們緊接著正則表示式了,所謂表示式意思就是用一些字元按照先後順序組合在一起表示的一層含義,所以我們先要重正則表示式的元字元說起,其實元字元就相當於javascript語言的關鍵字,比如你定義變數不能這樣幹 var if = "xxxx"; 正則有一下一些元字元:{ [ ^ | $ ] } ? * + . 這些都是正則的元字元,這裡我就不解釋意思了,用到了時候再來分析。如果大家想知道可以找度娘
字元類
字元類是用於測試字串的組合, 將一些字元放入方括號中,就可以有效的告訴正則表示式去匹配第一個,第二個,第三個...比如/[abc]/,這個又稱之為簡單類
簡單類:
var str = "cat 123 caT 234 cAt 345 CaT"; var reg = /cat/gi; str.match(reg) ; //out ["cat","caT","cAt","CaT"]
負向類和範圍類: 這裡要解釋下"^" "-"這兩個符號, "^"這個符號的意思就是取反,而"-"是範圍, g表示全域性,i表示忽略大小寫,/[^2-3a-z]+/gi 所以這句話的意思就是: 除了2到3和a到z的所有字元出現1次到多次,並且在全域性中忽略大小寫。其實細心的看官這裡還會發現一個知識點, 2-3a-z這一句其實是一個組合,又稱之為組合類,下面的這個例項就用到了正則的幾個知識點: 1.負向類,意思就是取反; 2. 範圍類; 3.組合類,相當於邏輯運算子的並且&&
var str = "cat123caT234cAt345CaT"; var reg = /[^2-3a-z]+/gi; str.match(reg); //out ["1","4","45"]
預定義類:
程式碼 等同於 匹配 . [^\n\r] 除了換行和回車符之外的任意字元\d [0-9] 數字\D [^0-9] 非數字字元\s [\t\n\x0b\f\r] 空白字元\S [^\t\n\x0b\f\r] 非空白字元\w [a-zA-Z_0-9] 單詞字元,所有的字元數字下劃線\W [^a-zA-Z_0-9] 非單詞字元
量詞:量詞是可以指某個特定模式出現的次數,可以是硬性量詞,比如某個字元出現三次,也可以是軟性量詞,比如某個字元至少出現一次。正則中的量詞有以下這些
貪婪量詞:
? 出現零次到一次
+ 至少出現一次或者多次
* 出現0次到多次
{n} 出現n次
{n,m}出現n次到m次
{n,} 至少出現n次或者n+次
說道量詞的話有貪婪, 惰性和支配量詞,以上的這些量詞都是貪婪量詞,由於javascript正則引擎對支配量詞支援不是很好,所以我們這裡重點來說貪婪和惰性量詞,先把惰性量詞列出來之後在來說說他們的關係和區別
惰性量詞:
?? 出現零次到一次
+? 至少出現一次或者多次
*? 出現零次到多次
{n}? 出現n次
{n,m}? 出現n次到m次
{n,}? 至少出現n次或者n+次
貪婪量詞在匹配字串的時候首先看是否匹配字串,如果沒有找到匹配的則去掉字串中最後一個字元再次嘗試,整個過程一直重複,直到字串為空時停止。而惰性量詞正好相反,首先檢視字串中第一個字元是否匹配,否則在讀入下一個字元在進行匹配,直至重複這個過程到讀入整個字元竄都不匹配時停止。可能說了這些多還是不太明白,下面我會舉個例子幫助大家理解
var str = "abbbaabbbaaabbb1234"; var re1 = /.*bbb/g; //貪婪匹配 var re2 = /.*?bbb/g; //惰性匹配 alert(str.match(re1)); alert(str.match(re2));
親,你覺得第一個alert會輸出什麼呢,如果是[abb,aabbb,aaabbb]的話的, 那麼恭喜你答錯了,前面說過*是貪婪量詞,它在匹配的時候會首先匹配整個字串,是從字串的尾部操作的,當去掉字元1的時候就發現剩下的字串"abbbaabbbaaabbb"已經達到它匹配的要求了,所以它返回的結果就是字串"abbbaabbbaaabbb",而第二個alert為啥子會列印[abbb,aaabbb]呢,我們再來一步一步的看,這個是惰性匹配,所以它在匹配字串的時候是從字串開始的部分取出第一個字元進行匹配,發現不行,在取下一個,還是不行,直至取到了"abbb".好,現在發現匹配了,然後將這個裝進陣列, 在從剩下的字串裡面取,直至最後將符合指定模式的子字串裝進陣列,所以最後就返回[abbb,aaabbb]。只要稍微花點心思動動手還是很容易就理解了。好了,關於正則的量詞的一些知識點就講到這裡,萬里長征才走一半,下面接到說正則的複雜模式,上面說到的字元類那一塊都是正則的簡單模式,只能做一些簡單的字母,數字,漢字,長度等效驗,如果在掌握了下面的複雜模式就可以非常牛逼的匹配各種複雜,蛋痛的字串模式了,比如郵箱,身份證驗證,標籤過濾,包括jquery類選擇器,sizzle引擎過濾器。好了,直接切入主題吧:
複雜分組
分組模式:分組模式就那麼回事我用一個例子或許你一下子就豁然開朗了
//如果要匹配"andand"的怎麼做呢,你也許會說可以這樣幹 var str = "asdfandandcxhksdf"; var reg = /andand/gi; alert(reg.test(str)); //output true //好的,親,這樣匹配也是可以的,但是有不知道多少and怎麼辦呢, //不可能全部加在正則表示式裡面吧,此時分組的便捷性就體現出了 //出了它的優勢,我們可以這樣幹: var reg = /(and){2}/g; //注意這裡()是元字元分組的意思,{2} 是量詞,貪婪量詞
捕獲分組模式:指的是RegExp.$1這個屬性的值,這個值就是正則中一個分組的值,在這個物件RegExp中,定義了最多支援RegExp.$1-RegExp.$100個分組值,還是來個例子吧
var str = "asdffirstfirstsecondsecond1234"; var reg = /(first){2}(second){2}/gi; reg test(str); // 要必須匹配之後才有下面的值 alert(RegExp $1); //output "first" alert(RegExp $2); //output "second"
非捕獲分組模式:上面說了捕獲分組,那非捕獲分組其實就是不讓RegExp.$1引用了,這裡要說一點的是在捕獲分組中RegExp.$1會建立正則的反向引用的儲存空間,所以在進行捕獲分組時會有更多的空間開銷,還會降低匹配速度。那現在曉得非捕獲分組的好處了吧。簡單的說就是在正則表示式()裡面加上一個問號和冒號/(?:first)/,語法就是這樣的,還是看程式碼吧
var str = "#123456789"; var reg = /#(?:\d+)/; reg.test(str); alert(RegExp.$1); //output "" 注意這裡取消了反向引用就為空了
候選模式:候選我的理解就是或者,舉個例子,比如你要對一個表示式同時匹配"red","black"的話怎麼做呢, 如果是在以前的話就要寫兩個正則來進行分別匹配,而加入了候選就可以非常方便的操作了,還是上程式碼吧
var str1 = "111red222"; var str2 = "111black111"; var reg = /(red|black)/; alert(reg.test(str2)); //output true alert(reg.test(str1)); //output true
前瞻模式:有時候我們希望某個字元分組出現在另外一個字元分組之前才去捕獲,這相當於是在正則裡面做判斷了, 果然是高階功能,灰常強大,我在寫正則的時候也沒有用到過, 只是書上都說了, 我還是把它搬到這裡來出哈風頭。 上程式碼吧
/* *前瞻又分為正向前瞻和反向前瞻 *下面我會用程式碼加註釋的方式加以描述 */ //正向前瞻 var str1 = "bedroom"; var str2 = "bedding"; var reg = /(bed(?=room))/; //符號?=來表示正向前瞻,表示在字串"bedroom"中如果bed後面有room的字元才捕獲,順序執行 alert(reg.test(str1)); //output true alert(RegExp.$1); //output "bed" 捕獲到反向引用bed字串 alert(reg.test(str2)); //output true //反向前瞻 var reg = /(bed(?!ing))/; //符號?!來表示反向前瞻,表示在字串"bedding"中如果有"ing"子字串才捕獲,逆序執行 alert(reg.test(str2)); //output true alert(RegExp.$1); //output "bed" 捕獲到反向引用bed字串 alert(reg.test(str1)); //output true alert(RegExp.$1); /*以上程式碼如果各位親測試不通過的話那就是正則引擎不支援前瞻*/
邊界模式:這個模式很重要也很常用,比如去掉字串的首尾空格,那下面說說幾種邊界的可能:
^行的開始 $行的結尾 \b單詞的邊界 \B非單詞的邊界
//用一個例子來說明邊界 var str = " xiaoming " var reg = /(^\s+)|\s+$/g; //(^\s+)去除字串開始位置的空格,\s+$去除字串尾部空格,|這個符號想必不用我說了吧,候選 var str = str.replace(reg,""); alert(str); //output "xiaoming"
多行模式:這個也是正則複雜模式裡面最後一個模式了,也不經常用,不管你信不信,反正我是信了,還是直接來看程式碼吧
//請看下面這個例項,\n在前面的預定類,表示換行 var str = "first\nsecond\nthread"; var reg = /^(\w+)/g; alert(str.match(reg)); //output 若不指定m行的話就輸出"first" var reg = /^(\w+)/gm; alert(str.match(reg)); //output [first,second,thread]
到目前為止正則表示式的語法,規則各種都已經說完了,如果各位小白認真的看到這裡,我們在來分析文章開頭說的郵箱驗證表示式就非常容易了。好,現在我們就來一步一步的分析那個非常蛋痛的表示式,首先我們要來拆分這段表示式,我會用不同的顏色來表示這段表示式的每一段,這裡就用到了一種思想,分而治之,太複雜的東西不利於直觀的表達某些東西,所以拆分,打碎,各個擊破:
/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/
1.([a-zA-Z0-9]+[_|\_|\.]?)* 這一段表示的是一個分組,分組()裡面首先是[a-zA-Z0-9]意思是匹配字串大小寫字母數字,後面緊跟一個+,這個是貪婪量詞,1次到多次,前面提到過的。[a-zA-Z0-9]+而這一段的意思就是說大小寫字母數字匹配1次到多次,[_|\_|\.]?而這個呢是符號"_"或者"."出現0次到一次。整個這段表示式的意思就是所有大小寫字母數字出現1次到多次,緊接著符號"_"和"."出現0次到一次,在把這兩個條件加起來成為一個組,這個組的格式又可以出現0次到多次。
2.[a-zA-Z0-9]+ 這段就不用說了吧,上面也說了就是大小寫字元數字出現1次到多次
3.@([a-zA-Z0-9]+[_|\_|\.]?)* 這個理解起來就簡單了,以字元@開頭上面那個分組出現0次到多次的這個格式
4.\.[a-zA-Z]{2,3} 這個表示式呢還是比較容易,也是以字元"."開頭所有大小寫字母出現兩次或者三次
5./^$/ 這兩個符號是表示從字串的開始匹配到行的結束。
看到這裡大家是不是對正則表示式的認識更深了一些呢, 如果還不行話在給大家分析一個例項吧 /^((0?[1-9])|((1|2)[0-9])|30|31)$/ 這個正則的意思是驗證一個月的31天,正確格式是01、09和1、31。首先我們還是來拆分 /^((0?[1-9])|((1|2)[0-9])|30|31)$/
1.首先這個表示式中出現了三個黑色的"|"候選符號,意思就是說可以匹配四種情況
2.(0?[1-9]) 這個表示式是匹配 0出現0次或者一次緊接著跟上數字出現一次,這是一種情況,如:01, 09,1,9這些
3.((1|2)[0-9]) 這個分組表示的是1或者2出現一次緊接著跟上0-9出現一個,又是一種情況,如:10,19,20,29
4.30|31 這個就更簡單了,30或者31只能出現一次。
到此這篇關於javascript中正則表示式語法詳解的文章就介紹到這了,更多相關javascript正則表示式內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!