瞭解RegExp類型: ECMAScript通過RegExp類型來支持正則表達式。 var expression=/pattern/flags; 正則表達式的模式(pattern)部分: 可以是任何簡單或複雜的正則表達式,可以包含字元類,限定符,分組,向前查找,反向引用。 關於正則表達式中各種特殊字
瞭解RegExp類型:
ECMAScript通過RegExp類型來支持正則表達式。 var expression=/pattern/flags;
正則表達式的模式(pattern)部分:
可以是任何簡單或複雜的正則表達式,可以包含字元類,限定符,分組,向前查找,反向引用。 關於正則表達式中各種特殊字元(如 \,^,$,\w,\b 等)的含義可以參考 MDN 正則表達式-特殊字元 的整理。這裡我們簡單介紹一下向前查找和反向引用。
- 向前查找:正則表達式向前使用一些字元而不移動這些字元的位置,分為正向前預搜索也叫正向肯定查找( x(?=y) )與負向前預搜索也叫正向否定查找( x(?!y) )。
- 反向引用:標識字元串中可以提供的重覆字元或字元串,可以使用捕獲組反向引用匹配。帶編號的反向引用 \number number是正則表達式中捕獲組的序號位置。
- 表達式 \1~\9 解釋為反向引用而不是八進位代碼。 /\b(\w+)\s\1/.exec('s_ s_');//["s_ s_", "s_"]
- 如果多位表達式的第一個數字是8或者9(如 \80 或 \91 ),則該表達式將被解釋為文本。 /\b(\w+)\s\80/.exec('s_ 800');//["s_ 80", "s_"]
- 對於編號為 \10 或更大值的表達式,如果存在與該編號對應的反向引用,則將該表達式視為反向引用。否則將這些表達式解釋為八進位。
/(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)xx\10/.exec('12345678910xx10');//["12345678910xx10", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] /(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)xx\11/.exec('12345678910xx10');//null
- 如果捕獲組嵌套捕獲組,捕獲組確定的順序是內部從外到內,外部從左到右。來個代碼體會一下。
/\b(\w+x(x))\s(\1)/.exec('s_xx s_xxSTOP');//["s_xx s_xx", "s_xx", "x", "s_xx"]
- 如果正則表達式包含對未定義的組成員的反向引用,則會發生分析錯誤,根據語言的不同正則表達式引擎將引發 ArgumentEXception 。對於javascript會返回null。/\b(\w+)\s\2/.exec('s_ 8');//null
- 參考:正則表達式中的反向引用構造 正則基礎之反向引用
- 反向引用實例代碼:捕獲組捕獲到的內容不僅可以在正則表達式外部通過程式進行引用( RegExp.$n )也可以在正則表達式內部進行引用( \number ,這種引用方式就是反向引用)。
//表達連續三個相同的小寫,{2}應用在\1身上 /([a-z])\1{2}/.exec('aaa');//["aaa", "a"]
//一道有意思的正則問題 /(\w)((?=\1\1\1)(\1))/.exec('aa bbbb');//["bb", "b", "b", "b"] /*這裡捕獲組有三個,$1為(\w)中的內容,$2為((?=\1\1\1)(\1))中的內容: 需註意(?=\1\1\1)並不是捕獲組而是正則表達式的判斷條件,x(?=y)表示匹配x僅僅當後面跟著y,判斷條件並不是匹配結果的一部分。所以現在$2的內容為(\1)即‘b’。$3就是\1的內容。返回的匹配項 “bb”中的第一個'b'為"aa bbbb"中的第一個'b',第二個'b'為"aa bbbb"中的第二個'b'。*/ /(\w)(x(?=\1\1\1)(\1))/.exec('aa bxbbbcb');//["bxb", "b", "xb", "b"] //這裡$2的內容為(x(?=\1\1\1)(\1))中的內容即x(\1); //其實上面兩種模式可以簡化成/(\w)(?=\1\1\1)(\1)/表示匹配\w僅當該\w後後面跟著三個\1,然後獲取的匹配項為該\w且其後再緊跟著\1的字元串。同理/(\w)x(?=\1\1\1)(\1)/
/(\w)((?=\1\1\1)(\2))/.exec('aa bbbbv');//["b", "b", "", ""] /*捕獲組$2為((?=\1\1\1)(\2))中的內容,由於此時還未執行完捕獲組$2處的匹配,所以\2表示""。$3即為\2的內容還是""。所以這條匹配被解釋為返回\w且其後緊跟3個該\w的字元串,返回\w+''就只返回'b'了。*/
正則表達式的標誌位(flags)部分:
可以帶有一個或多個標誌,用以表明正則表達式的行為。
- g:表示全局模式,模式將被應用於所有字元串,而非在發現第一個匹配項時立即停止。 'cat mat bat'.replace(/.(?=at)/g,'A');//"Aat Aat Aat"
- i:不區分大小寫模式,在確定匹配項時忽略模式與字元串的大小寫。 'cAt mat bAt'.replace(/a/gi,'B');//"cBt mBt bBt"
- m:多行模式,在到達一行文本末尾時還會繼續查找下一行中是否存在與模式匹配的項。
var str='cat\nmat\nbat'; str.replace(/at/gm,'AB'); /*"cAB mAB bAB"*/
正則表達式中的元字元部分:
在模式中使用這些元字元時必須轉義,如果想要匹配的字元串中包含這些字元,就需要對他們進行轉義。
-
( [ { \ ^ $ | ) ? * + . ] }
//匹配"[bc]at" /\[bc\]at/.exec("xx[bc]at");//["[bc]at"] //匹配".at" /\.at/.exec("xx.at");//[".at"]
創建正則表達式:
- 字面量形式 :形如 var expression=/pattern/flags;
- RegExp構造函數:兩個參數(要匹配的字元串模式,可選的標誌字元串),不能把正則表達式字面量傳遞給構造函數,雖然即使這樣寫了也不會報錯。可以使用字面量定義的任何表達式都可以使用構造函數來定義。如下:
var p=/[bc]at/; new RegExp('[bc]at');// /[bc]at/
- 當不傳任何參數或參數一為空字元串時, new RegExp();// /(?:)/ 或 new RegExp('');// /(?:)/ ,表示匹配 "" 但不記住匹配項( "" 其實就是 ":" 之後的空串,不記住x匹配項的規則為(?:x)),所以在匹配任何字元串時都返回 [""] 。所以由此可以猜想一下javascript正則引擎內部機制應該是預設匹配 "" 且不記住該匹配項,除非顯式聲明在 ":" 之後的需要匹配的字元串,加上 "(?:)" 顯式聲明不記住匹配項。
- 由於構造函數模式參數是字元串,所以某些情況下(是指那些已經轉義過的字元)對字元進行雙重轉義(即在字面量形式的單重轉義再來一層轉義)。某些情況下當然也可以進行單重轉移( new RegExp('\w');// /w/ )。註意'\'比較特殊,在字元串中也需要進行轉義。
var p=/\\n/;//轉義\,字元"\"在字元串中常需要被轉義為"\\" p.exec("\\nxx");//["\n"] var p=new RegExp("\\\\n");// /\\n/ 如果想獲得正則表達式字面量為/\\n/,需要在正則表達式中再來一層轉義 p.exec('\\nxx');//["\n"] 註意被匹配的字元串'\nxx'中\n的\也被轉義了 new RegExp('\\n').exec("\n");// [" "] /*RegExp('\\n')返回/\n/,即意思匹配換行符*/ new RegExp('\n').exec("\n");// [" "] /*new RegExp('\n')返回 / / ,表示並沒有進行轉義,而是返回字面量
/
/,意思匹配換行符 */ - 下麵給出一些單重,雙重轉義模式的參考:第幾次轉義在表中已標出,單代表第一次轉義,雙代表在已經有的轉義的基礎上再進行的轉義。
字面量模式 等價的字元串 /\[bc\]at/ "\\[bc\\]at" /\.at/ "\\.at" /name\/age/ "name\\/age" /\d.\d{1,2}/ "\\d.\\d{1,2}" 單 /\w\\hello\\123/ "\\w\\\\hello\\\\123" 單+雙
RegExp的實例屬性:
通過實例的屬性可以獲取有關模式的各種信息
- global :布爾值,表示是否設置了g標誌。
- ignoreCase :布爾值,表示是否設置了i標誌。
- multiline :布爾值,表示是否設置了m標誌。
- lastIndex :整數,表示開始搜索下一個匹配項的字元位置,從0算起。前提是設置g標誌時才會有用。
- source :正則表達式的字元串標誌,按照字面量形式而非構造函數中的字元串模式返回字元串。
new RegExp('\\\\w');// /\\w/ 返回自面量形式正則表達式 new RegExp('\\\\w').source;// "\\w" 字元串
RegExp的實例方法:
- exec():該方法是專門為捕獲組而設計的,參數為要匹配的字元串,返回包含第一個匹配項信息和可能有的捕獲組的數組,若未匹配到返回 null 。(返回的雖然是 Array 的實例,但還包含兩個額外的屬性: index 表示匹配項在字元串中的位置, input 表示應用正則表達式的字元串)
var arr=new RegExp('\\\\(w)').exec('\\w');// ["\w", "w"] arr;// ["\w", "w"] arr.index;//0 arr.input;// "\w" 即exec()里的內容
exec() 和 match() 方法的區別:
-
對於 exec() 而言,即使在模式中設置了全局標誌g,它每次也只返回一個匹配項;字元串的 match() 方法在設置g的時候可以返回全部匹配項而沒有捕獲組且返回的數組沒有index和input屬性。
-
對於exec()而言可以返回捕獲組,但match()在沒有全局g標誌時才能返回捕獲組,此時match()返回的數組有index和input屬性。
//返回全局匹配項演示比較 var arr='ababcdab'.match(/ab/g);// ["ab", "ab", "ab"] arr.index; // undefined arr.input; // undefined /ab/g.exec('ababcdab');// ["ab"] //捕獲組演示比較,match()方法和有無設置全局g標誌有關 'ababcdab'.match(/a(b)/g);// ["ab", "ab", "ab"] var arr='ababcdab'.match(/a(b)/);// ["ab", "b"] arr.index;// 0 arr.input;// 'ababcdab' /a(b)/g.exec('ababcdab');// ["ab", "b"]
-
所以在選擇使用方法的時候要先考慮好側重該方法的哪方面功能,在不設置全局標誌g的情況下,在同一個字元串上多次調用exec()則總是返回第一個匹配項的信息,而在設置全局標誌的情況下,每次調用exec()則都會在字元串中沿著上次查找的位置往後繼續查找新的匹配項。
//未設全局,每次從頭開始查找 var p=/a/; var str='ababa'; var a=p.exec(str);// ["a"]; var b=p.exec(str);// ["a"]; a==b;// false a.index==b.index;// true //設置全局,沿著上次位置繼續查找新匹配 var p=/a/g; var str='ababa'; var a=p.exec(str);// ["a"] a.index;// 0 var b=p.exec(str);// ["a"] b.index;// 2
- test():接收字元串參數,在模式與字元串參數匹配情況下返回 true ,否則返回 false 。常被用在 if() 中當判斷條件。
var text="000-000-000"; var p=/((\d{3})-)\1*\2/; if(p.test(text)){ console.log('匹配成功'); }
- RegExp 實例繼承 Object 的 toLocaleString() 和 toString() 方法都會返回正則表達式的字面量形式的字元串,與如何創建正則表達式的方式無關。 valueOf() 則返回正則表達式字面量本身。
var p=/\[new\]bi/; p.toLocaleString();// "/\[new\]bi/" p.toString();// "/\[new\]bi/" p.valueOf();// /\[new\]bi/ var p=new RegExp('\\[new\\]bi'); p.toLocaleString();// "/\[new\]bi/" p.toString();// "/\[new\]bi/" p.valueOf();// /\[new\]bi/
RegExp的構造函數屬性:
構造函數本身包含一些屬性(靜態屬性),這些屬性適用於作用域中的所有表達式,並且基於所執行的最近一次正則表達式操作而變化。有長屬性名(如下代碼)和短屬性名(即$首碼形式,由於這些符號大多不是有效的ECMAScript標識符,所以不能直接在 RegExp 構造函數上以 "." 的方式訪問,而要通過方括弧語法來訪問)兩種方式訪問這些屬性
-
/(.)hort/g.exec('this is a short day');// ["short", "s"] //最近一次要匹配的字元串 RegExp.input;// "this is a short day" 或RegExp["$_"]訪問; //最近一次的匹配項 RegExp.lastMatch;// "short" 或RegExp["$&"]訪問; //在最近一次要匹配的字元串中的最近一次匹配項之前的文本 RegExp.leftContext;// "this is a " 或RegExp["$`"]訪問; //在最近一次要匹配的字元串中的最近一次匹配項之後的文本 RegExp.rightContext;// " day" 或RegExp["$'"]訪問; //最近一次(最後一次)匹配的捕獲組 RegExp.lastParen;// "s" 或RegExp["$+"]訪問;
捕獲組訪問屬性:還有9個用於存儲捕獲組的構造函數屬性,訪問語法是 RegExp.$n ,其中n取值1~9,用於獲取第n個匹配的捕獲組。在調用 exec() , test() 或 match() 等正則系列方法時這些屬性會被自動填充。
var text="this is a short summer"; var pattern =/(..)or(.)/g; if(pattern.test(text)){ console.log(RegExp.$1); // sh console.log(RegExp.$2); // t }
模式的局限性:
缺少一些高級正則表達式的特性,如不支持向後查找,命名的捕獲組(形如 \k<name> 引用之前名為 name 的捕獲組的字元串)等。
參考:
- 《javascript高級程式設計》
- MDN RegExp
- MDN 正則表達式
- javascript正則表達式詳解
- javascript正則表達式下相關方法