精通 JS正則表達式 (精通?標題黨 )
正則表達式能夠:
•測試字符串的某個模式。例如,能夠對一個輸入字符串進行測試,看在該字符串是否存在一個電話號碼模式或一個信用卡號碼模式。這稱爲數據有效性驗證
•替換文本。能夠在文檔中使用一個正則表達式來標識特定文字,而後能夠所有將其刪除,或者替換爲別的文字
•根據模式匹配從字符串中提取一個子字符串。能夠用來在文本或輸入字段中查找特定文字
正則表達式語法
一個正則表達式就是由普通字符(例如字符 a 到 z)以及特殊字符(稱爲元字符)組成的文字模式。該模式描述在查找文字主體時待匹配的一個或多個字符串。正則表達式做爲一個模板,將某個字符模式與所搜索的字符串進行匹配。
建立正則表達式 javascript
RegExp構造函數第一個參數爲正則表達式的文本內容,而第一個參數則爲可選項標誌.標誌能夠組合使用
•g (全文查找)
•i (忽略大小寫)
•m (多行查找)
html
正則表達式還有另外一種正則表達式字面量的聲明方式 java
和正則表達式相關的方法和屬性
正則表達式對象的方法
•test,返回一個 Boolean 值,它指出在被查找的字符串中是否存在模式。若是存在則返回 true,不然就返回 false。
•exec,用正則表達式模式在字符串中運行查找,並返回包<script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>含該查找結果的一個數組。
•compile,把正則表達式編譯爲內部格式,從而執行得更快。
正則表達式對象的屬性
•source,返回正則表達式模式的文本的複本。只讀。
•lastIndex,返回字符位置,它是被查找字符串中下一次成功匹配的開始位置。
•$1...$9,返回九個在模式匹配期間找到的、最近保存的部分。只讀。
•input ($_),返回執行規範表述查找的字符串。只讀。
•lastMatch ($&),返回任何正則表達式搜索過程當中的最後匹配的字符。只讀。
•lastParen ($+),若是有的話,返回任何正則表達式查找過程當中最後括的子匹配。只讀。
•leftContext ($`),返回被查找的字符串中從字符串開始位置到最後匹配以前的位置之間的字符。只讀。
•rightContext ($'),返回被搜索的字符串中從最後一個匹配位置開始到字符串結尾之間的字符。只讀。
String對象一些和正則表達式相關的方法
•match,找到一個或多個正則表達式的匹配。
•replace,替換與正則表達式匹配的子串。
•search,檢索與正則表達式相匹配的值。
•split,把字符串分割爲字符串數組。
測試正則表達式是如何工做的! 正則表達式
固然,僅僅知道了字符串是否匹配模式還不夠,咱們還須要知道哪些字符匹配了模式
chrome
更復雜的用法,使用子匹配 express
注意,當字符串不匹配re時,exec方法將返回null
String對象的一些和正則表達式有關的方法 編程
注意,當search方法沒有找到匹配時,將返回-1
相似於exec方法,String對象的match方法也用於將字符串與正則表達式進行匹配並返回結果數組 數組
RegExp對象實例的一些屬性 編程語言
每一個RegExp對象的實例具備lastIndex屬性,它是被查找字符串中下一次成功匹配的開始位置,默認值是-1。 lastIndex 屬性被 RegExp 對象的 exec 和 test 方法修改.而且它是可寫的. 函數
當匹配失敗(後面沒有匹配),或lastIndex值大於字符串長度時,再執行exec等方法會將lastIndex設爲0(開始位置)
RegExp對象的靜態屬性
multiline屬性返回正則表達式是否使用多行模式,這個屬性不針對某個正則表達式實例,而是針對全部正則表達式,而且這個屬性可寫.(IE與Opera不支持這個屬性)
使用元字符注意事項:元字符是正則表達式的一部分,當咱們要匹配正則表達式自己時,必須對這些元字符轉義.下面是正則表達式用到的全部元字符
( [ { \ ^ $ | ) ? * + .
使用RegExp構造函數與使用正則表達式字面量建立正則表達式注意點
既然雙重轉義這麼不友好,因此仍是用正則表達式字面量的聲明方式
如何在正則表達式中使用特殊字符?
另處,還有一些其它的預約義特殊字符,以下表所示:
字符 描述
\n 換行符
\r 回車符
\t 製表符
\f 換頁符(Tab)
\cX 與X對應的控制字符
\b 退格符(BackSpace)
\v 垂直製表符
\0 空字符("")
字符類 ---〉簡單類,反向類,範圍類,組合類,預約義類
下面是正則表達式中的預約義類
代碼 等同於 匹配
. IE下[^\n],其它[^\n\r] 匹配除換行符以外的任何一個字符
\d [0-9] 匹配數字
\D [^0-9] 匹配非數字字符
\s [ \n\r\t\f\x0B] 匹配一個空白字符
\S [^ \n\r\t\f\x0B] 匹配一個非空白字符
\w [a-zA-Z0-9_] 匹配字母數字和下劃線
\W [^a-zA-Z0-9_] 匹配除字母數字下劃線以外的字符
量詞(下表量詞單個出現時皆是貪婪量詞)
代碼 描述
* 匹配前面的子表達式零次或屢次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等價於{0,}。
+ 匹配前面的子表達式一次或屢次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。
? 匹配前面的子表達式零次或一次。例如,"do(es)?" 能夠匹配 "do" 或 "does" 中的"do" 。? 等價於 {0,1}。
{n} n 是一個非負整數。匹配肯定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',可是能匹配 "food" 中的兩個 o。
{n,} n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的全部 o。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。
{n,m} m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。劉, "o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。
貪婪量詞與惰性量詞
•用貪婪量詞進行匹配時,它首先會將整會字符串當成一個匹配,若是匹配的話就退出,若是不匹配,就截去最後一個字符進行匹配,若是不匹配,繼續將最後一個字符截去進行匹配,直到有匹配爲止。直到如今咱們遇到的量詞都是貪婪量詞
•用惰性量詞進行匹配時,它首先將第一個字符當成一個匹配,若是成功則退出,若是失敗,則測試前兩個字符,依些增長,直到遇到合適的匹配爲止
惰性量詞僅僅在貪婪量詞後面加個"?"而已,如"a+"是貪婪匹配的,"a+?"則是惰性的
多行模式
分組與非捕獲性分組
候選(也就是所說的「或」)
當包含分組的正則表達式進行過test,match,search這些方法以後,每一個分組都被放在一個特殊的地方以備未來使用,這些存儲是分組中的特殊值,咱們稱之爲反向引用
使用反向引用能夠要求字符串中某幾個位置上的字符必須相同.另外,在replace這類方法中可用特殊字符序列來表示反向引用
其它——〉正向前瞻,用來捕獲出如今特定字符以前的字符,只有當字符後面跟着某個特定字符纔去捕獲它。與正向前瞻對應的有負向前瞻,它用匹配只有當字符後面不跟着某個特定字符時纔去匹配它。在執行前瞻和負向前瞻之類的運算時,正則表達式引擎會留意字符串後面的部分,然而卻不移動index
構建一個驗證電子郵箱地址有效性的正則表達式。電子郵箱地址有效性要求(咱們姑且這樣定義):用戶名只能包含字母數字以及下劃線,最少一位,最多25位,用戶名後面緊跟@,後面是域名,域名名稱要求只能包含字母數字和減號(-),而且不能以減號開頭或結尾,而後後面是域名後綴(能夠有多個),域名後綴必須是點號連上2-4位英文字母
出處:http://www.iteye.com/topic/481228/
===============================================================
在javascript咱們能夠經過內建的類來定義一個正則表達式。
1 |
var reName = new RegExp( "nowamagic" ); |
實際上RegExp類的構造函數能夠接受兩個參數,除了自己須要匹配的模式字符串外,還能夠定義指定額外處理方式的第二個參數。
1 |
var reName = new RegExp( "nowamagic" , "i" ); //忽略大小寫 |
我很好奇輸出reName會獲得什麼結果呢?因而:
1 |
document.write(reName); |
獲得結果:/nowamagic/i,因而咱們獲得javascript中正則表達式的第二種定義方法(perl風格):
1 |
var reName = /nowamagic/; |
那第二個參數呢?固然,一樣能夠爲其指定第二個參數:
1 |
var reName = /nowamagic/i; |
這兩種定義方式都是可行的,徹底能夠根據我的習慣進行選擇。就像可使用var s = new String(「for a simple life」);定義字符串的同時還可使用var s = 「for a simple life」;來定義是徹底相同的。建議使用perl風格的寫法,除了簡潔外,還省去了使用RegExp構造函數定義時須要對「\」轉義的麻煩。
若是要匹配字符「\」,perl風格的寫法是:
1 |
var res = /\\/; |
而構造函數的寫法則須要對兩個「\」都進行轉義:
1 |
var res = new RegExp( "\\\\" ); |
感受上是否是就麻煩了不少?
記住,在一個完整的正則表達式中「\」後面老是跟着另一個字符。
其實上面已經在開始講了javascript對正則表達式的實現方式了,只定義了正則表達式,可是如何在javascript中真正使用正則表達式呢?在javascript中RegExp和String對象都有處理正則表達式的方法。
關於這些函數的具體使用方法,能夠參閱JS的相關函數手冊。
一個實例對象除了方法固然還有屬性,一個正則表達式有如下屬性:
在正則表達式中有一些特殊的字符符號咱們是不能直接使用的,必須對其進行轉義後才能使用。如「\」,由於這些字符在正則表達式中有特殊的語法含義,這類字符被稱爲元字符,正則表達式中的元字符有:
1 |
.,\,/,*,?,+,[,(,),],{,},^,$,| |
可能不太好記憶,當沒法肯定某個字符是不是元字符的時候就勇敢的對其進行轉義是沒有錯的,對不是元字符的字符進行轉義是不會出什麼問題的,可是若是不對元字符轉義就會有意想不到的錯誤產生了。
一個簡單的字符就能夠是一個匹配模式,可是現實狀況每每不會這麼簡單。好比咱們要匹配一個0-9的數字:
1 |
var i = 5; |
2 |
var j = 6; |
這個正則表達式要如何書寫才能同時匹配這兩個數字呢?簡單的字符表達式固然沒法完成了,這個時候咱們就能夠爲0-9十個數字來定義一個字符集合(字符類)來進行匹配。
1 |
var reNum = /[0123456789]/; |
2 |
document.write(reNum.test(i)); //true |
3 |
document.write(reNum.test(j)); //true |
使用test方法測試匹配結果都輸出了true。
上一個例子使用了分組匹配,可是若是要匹配全部26個英文字母,還要包括大小寫,仍然可使用分組匹配:
1 |
var reLetter = /abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/; |
恩,這個正則表達式是徹底正確的,可是是否是感受太長了,有沒有辦法讓它更爲簡潔一點?固然是有的,爲字符或數字指定一個匹配範圍就能夠了。
1 |
var reNum = /[0-9]/; |
2 |
var reLetter = /[a-zA-Z]/; |
這樣就能夠了,「-」用來定義一個匹配區間,字符的具體順序由ASCII字符表肯定,因此不能寫成/A-z/,由於Z-a之間還包含着其餘字符。
不少編程語言中都使用「!」取非操做,包括javascript。正則表達式中也有取非操做,好比/[^0-9]/就是一個取非操做的正則表達式了。
1 |
var i = 5; |
2 |
var s = "o" ; |
3 |
var rec = /[^0-9]/; |
4 |
document.write(rec.test(i)); //false |
5 |
document.write(rec.test(s)); //true |
符號^用來完成取非操做,同時^0-9也是必須包含在[]中的,由於^其實還有另一種特殊用途。
可能你以爲/[a-zA-Z]/,/[0-9]/仍是不夠簡潔,的確,在正則表達式中一些特定的字符集合可使用一些特殊的元字符來代替。這些特殊的字符並非必不可少的,可是卻能夠給咱們帶來很多方便。/[0-9]/就徹底能夠寫成這樣:
1 |
var reNum = /\d/; |
那大小寫字母字符類呢?很遺憾,除了POSIX字符類(javascript不支持POSIX字符類)中有支持大小寫字母的特殊字符類外並無專門替代方法。
常見的特殊字符有:
相同字母大小寫老是進行取非操做的。
在正則表達式中使用十六進制或八進制字符也是徹底可行的,他們所匹配的字符便是由其轉換成十進制後的數值在ASCII中所對應的字符。
1 |
var reAt = /\x40/; //十六進制字符\x40(64)對應字符「@」 |
2 |
var reA = /\0101/; //八進制字符\0101(65)對應字符「A」 |
以匹配一個email地址爲例,mymail@mail.com這樣的一個email地址必須包括一個合法的用戶名mymail,@符號以及一個合法的域。其中用戶名和域名的字符個數都是沒法判斷的,可是有一點是確定的——用戶名必須至少是一個字符,域名至少是兩個字符中間還必須有一個點號。因而咱們能夠這樣作:
1 |
var reMail = /\w+@\w+\.\w+/i; |
2 |
var email = "mymail@mail.com" ; |
3 |
document.write(reMail.test(email)); //true |
「+」表示字符出現一次或屢次,至少出現一次。這個正則表達式其實並不能匹配全部合法的email地址,後面咱們繼續完善。
除了「+」能夠指定至少匹配一次外,還有不少其餘的能夠指定匹配次數的方式。
www.gogle.com,www.google.com,www.gooogle.com這三個網址都能正確地打開google的首頁,因而就能夠用{n,m}匹配其中的1個,2個或3個字母」o」。
1 |
var gogle = "www.gogle.com" ; |
2 |
var google = "www.google.com" ; |
3 |
var gooogle = "www.gooogle.com" ; |
4 |
var reGoogle = /w{3}\.go{1,3}gle\.com/i; |
5 |
document.write(reGoogle.test(gogle)); //true |
6 |
document.write(reGoogle.test(google)); //true |
7 |
document.write(reGoogle.test(gooogle)); //true |
在上面的正則表達式中,咱們使用了{3}來制定字符「w」能且只
能出現3次,用{1,3}來制定字母「o」能夠出現1到3次。
有這樣一段HTML文本:
1 |
var html = "<em>nowamagic</em>for a simple life<em>http://nowamagic.net/</em>" ; |
若是如今要講<em></em>及其中間的文本匹配出來,正則表達式能夠這樣寫:
1 |
var reEm1 = /<em>.*<\/em>/gi; |
2 |
document.write(html.match(reEm1)); //"<em>nowamagic</em>for a simple life<em>http://nowamagic.net/</em>" |
3 |
var reEm2 = /<em>.*?<\/em>/gi; |
4 |
document.write(html.match(reEm2)); //<em>nowamagic</em>,<em>http://nowamagic.net/</em> |
當使用貪婪模式的時候,」.*」會最大程度地進行字符匹配,因此輸出了整個字符串。而在惰性模式中,」.*?」只進行最小限度的匹配,因此完整的輸出了咱們須要的字符串。
惰性模式的語法很簡單,便是在貪婪模式後面加上一個「?」便可。
1 |
var s = 「_Don’t do it!」; |
如何將單詞「do」匹配出來?it’s easy!
1 |
var reDo = / do /gi; |
2 |
document.write(s.match(reDo)); //Do,do |
可是這個簡單的正則表達式/do/gi將「don’t」中的「do」也進行了匹配,可這並非想要的結果。而在正則表達式中有專門用來進行單詞邊界匹配的限定符」\b「。
1 |
var reDo = /\bdo\b/gi; |
2 |
document.write(s.match(reDo)); //do |
「\b」到底匹配的什麼呢?」\b」匹配的是一個位置,一個位於」\w「(字母,數字,下劃線)和」\W「之間的位置。
既然有」\b」,那有」\B」嗎?固然,他和」\b「恰好相反,由來匹配一個不是單詞邊界的位置。好比上例中匹配」don’t」中的」do」時」\B」就可派上用場。
1 |
var reDo = /\Bdo\B/gi; |
2 |
document.write(s.match(reDo)); //Do |
在介紹取非匹配的時候介紹^只用位於[]並緊跟[方能取非匹配,而^還有另一種用途——字符串邊界匹配。
好比咱們要匹配一個http://nowamagic.net形式的net域名:
1 |
var url = "http://nowamagic.net" ; |
2 |
var reUrl = /^(http):\/\/nowamagic\.(net)$/gi; |
3 |
document.write(reUrl.test(url)); //true |
正則表達式reUrl限制url必須以」http」開頭,以」net」結尾。
又如常常被擴展的string方法trim:
1 |
function trim(s){ |
2 |
return s.replace(/(^\s*)|(\s*$)/g, "" ); |
3 |
} |
同時咱們能夠在整個模式的最前面使用(?m)來啓用分行匹配模式。這樣,^不但匹配正常的字符串開頭,還將匹配行分隔符(換行符)後面的開始位置;$不只匹配正常的字符串結尾,還將匹配行分隔符(換行符)後面的結束位置。
此文章所在專題列表以下:
出處:http://www.nowamagic.net/librarys/veda/detail/1283
=============================================================================
若是說這是一篇關於正則表達式的小結,我更願意把它當作一個手冊。
本文的RegExp採用直接量語法表示:/pattern/attributes。attributes有三個選擇,i、m和g,m(多行匹配)不經常使用直接省略,因此一個pattern(匹配模式)能夠表示以下:
var pattern = /hello/ig;
i(ignore)表示不區分大小寫(地搜索匹配),比較簡單,如下例子中不加述說;g(global)表示全局(搜索匹配),即找到一個後繼續找下去,相對複雜,如下各類方法中會特別介紹。
既然是RegExp的三大方法,因此都是pattern.test/exec/complie的格式。
主要功能:檢測指定字符串是否含有某個子串(或者匹配模式),返回true或者false。
示例以下:
var s = 'you love me and I love you'; var pattern = /you/; var ans = pattern.test(s); console.log(ans); // true
若是attributes用了g,則能夠繼續找下去,其中還會涉及lastIndex屬性(參照exec中搭配g的介紹)。
主要功能:提取指定字符串中的符合要求的子串(或者匹配模式),返回一個數組存放匹配結果;若是沒有,則返回null。(也可本身寫方法循環提取全部或者指定index的數據)
exec能夠說是test的升級版本,由於它不只能夠檢測,並且檢測到了能夠直接提取結果。
示例以下:
var s = 'you love me and I love you'; var pattern = /you/; var ans = pattern.exec(s); console.log(ans); // ["you", index: 0, input: "you love me and I love you"] console.log(ans.index); // 0 console.log(ans.input); // you love me and I love you
輸出的東西頗有意思。此數組的第 0 個元素是與正則表達式相匹配的文本,第 1 個元素是與 RegExpObject 的第 1 個子表達式相匹配的文本(若是有的話),第 2 個元素是與 RegExpObject 的第 2 個子表達式相匹配的文本(若是有的話),以此類推。
啥叫「與子表達式相匹配的文本」?看下面的例子:
var s = 'you love me and I love you'; var pattern = /y(o?)u/; var ans = pattern.exec(s); console.log(ans); // ["you", "o", index: 0, input: "you love me and I love you"] console.log(ans.length) // 2
所謂的子表達式就是pattern裏()內的東西(具體能夠參考下文對子表達式的介紹)。再看上面例子的數組長度,是2!!index和input只是數組屬性(chrome中以上的輸出可能會讓人誤會)。
除了數組元素和 length 屬性以外,exec() 方法還返回兩個屬性。index 屬性聲明的是匹配文本的第一個字符的位置。input 屬性則存放的是被檢索的字符串 string。咱們能夠看得出,在調用非全局的 RegExp 對象的 exec() 方法時,返回的數組與調用方法 String.match() 返回的數組是相同的。
若是使用 「g」 參數,exec() 的工做原理以下(仍是以上的例子 ps:若是test使用g參數相似):
當 RegExpObject 是一個全局正則表達式時,exec() 的行爲就稍微複雜一些。它會在 RegExpObject 的 lastIndex 屬性指定的字符處開始檢索字符串 string。當 exec() 找到了與表達式相匹配的文本時,在匹配後,它將把 RegExpObject 的 lastIndex 屬性設置爲匹配文本的最後一個字符的下一個位置。這就是說,咱們能夠經過反覆調用 exec() 方法來遍歷字符串中的全部匹配文本。當 exec() 再也找不到匹配的文本時,它將返回 null,並把 lastIndex 屬性重置爲 0。這裏引入lastIndex屬性,這貨只有跟g和test(或者g和exec)三者搭配時纔有做用。它是pattern的一個屬性,一個整數,標示開始下一次匹配的字符位置。
實例以下:
var s = 'you love me and I love you'; var pattern = /you/g; var ans; do { ans = pattern.exec(s); console.log(ans); console.log(pattern.lastIndex); } while (ans !== null)
結果以下:
應該還容易理解,當第三次循環時,找不到「you」了,因而返回null,lastIndex值也變成0了。
若是在一個字符串中完成了一次模式匹配以後要開始檢索新的字符串(仍然使用舊的pattern),就必須手動地把 lastIndex 屬性重置爲 0。
主要功能:改變當前匹配模式(pattern)
這貨是改變匹配模式時用的,用處不大,略過。詳見JavaScript compile() 方法
和RegExp三大方法平起平坐的是String的四大護法,四大護法有些和RegExp三大方法相似,有的更勝一籌。
既然是String家族下的四大護法,因此確定是string在前,即str.search/match/replace/split形式。
既然是String的方法,固然參數能夠只用字符串而不用pattern。
主要功能:搜索指定字符串中是否含有某子串(或者匹配模式),若有,返回子串在原串中的初始位置,如沒有,返回-1。
是否是和test相似呢?test只能判斷有木有,search還能返回位置!固然test()若是有須要能繼續找下去,而search則會自動忽略g(若是有的話)。實例以下:
var s = 'you love me and I love you'; var pattern = /you/; var ans = s.search(pattern); console.log(ans); // 0
話說和String的indexOf方法有點類似,不一樣的是indexOf方法能夠從指定位置開始查找,可是不支持正則。
主要功能:和exec相似,從指定字符串中查找子串或者匹配模式,找到返回數組,沒找到返回null
match是exec的輕量版,當不使用全局模式匹配時,match和exec返回結果一致;當使用全局模式匹配時,match直接返回一個字符串數組,得到的信息遠沒有exec多,可是使用方式簡單。
實例以下:
var s = 'you love me and I love you'; console.log(s.match(/you/)); // ["you", index: 0, input: "you love me and I love you"] console.log(s.match(/you/g)); // ["you", "you"]
主要功能:用另外一個子串替換指定字符串中的某子串(或者匹配模式),返回替換後的新的字符串 str.replace(‘搜索模式’,'替換的內容’) 若是用的是pattern而且帶g,則所有替換;不然替換第一處。
實例以下:
var s = 'you love me and I love you'; console.log(s.replace('you', 'zichi')); // zichi love me and I love you console.log(s.replace(/you/, 'zichi')); // zichi love me and I love you console.log(s.replace(/you/g, 'zichi')); // zichi love me and I love zichi
若是須要替代的內容不是指定的字符串,而是跟匹配模式或者原字符串有關,那麼就要用到$了(記住這些和$符號有關的東東只和replace有關哦)。
怎麼用?看個例子就明白了。
var s = 'I love you'; var pattern = /love/; var ans = s.replace(pattern, '$`' + '$&' + "$'"); console.log(ans); // I I love you you
沒錯,’$`’ + ‘$&’ + 「$’」其實就至關於原串了!
replace的第二個參數還能是函數,看具體例子前先看一段介紹:
注意:第一個參數是匹配到的子串,接下去是子表達式匹配的值,若是要用子表達式參數,則必需要有第一個參數(表示匹配到的串),也就是說,若是要用第n個參數表明的值,則左邊參數都必須寫出來。最後兩個參數跟exec後返回的數組的兩個屬性差很少。
var s = 'I love you'; var pattern = /love/; var ans = s.replace(pattern, function(a) { // 只有一個參數,默認爲匹配到的串(如還有參數,則按序表示子表達式和其餘兩個參數) return a.toUpperCase(); }); console.log(ans); // I LOVE you
主要功能:分割字符串
字符串分割成字符串數組的方法(另有數組變成字符串的join方法)。直接看如下例子:
var s = 'you love me and I love you'; var pattern = 'and'; var ans = s.split(pattern); console.log(ans); // ["you love me ", " I love you"]
若是你嫌獲得的數組會過於龐大,也能夠本身定義數組大小,加個參數便可:
var s = 'you love me and I love you'; var pattern = /and/; var ans = s.split(pattern, 1); console.log(ans); // ["you love me "]
什麼是貪婪匹配?貪婪匹配就是在正則表達式的匹配過程當中,默認會使得匹配長度越大越好。
var s = 'hello world welcome to my world'; var pattern = /hello.*world/; var ans = pattern.exec(s); console.log(ans) // ["hello world welcome to my world", index: 0, input: "hello world welcome to my world"]
以上例子不會匹配最前面的hello world,而是一直貪心的日後匹配。
那麼我須要最短的匹配怎麼辦?很簡單,加個‘?’便可,這就是傳說中的懶惰匹配,即匹配到了,就不日後找了。
var s = 'hello world welcome to my world'; var pattern = /hello.*?world/; var ans = pattern.exec(s); console.log(ans) // ["hello world", index: 0, input: "hello world welcome to my world"]
懶惰限定符(?)添加的場景以下:
用一個小括號指定:
var s = 'hello world'; var pattern = /(hello)/; var ans = pattern.exec(s); console.log(ans);
在exec中數組輸出子表達式所匹配的值:
var s = 'hello world'; var pattern = /(h(e)llo)/; var ans = pattern.exec(s); console.log(ans); // ["hello", "hello", "e", index: 0, input: "hello world"]
在replace中做爲替換值引用:
var s = 'hello world'; var pattern = /(h\w*o)\s*(w\w*d)/; var ans = s.replace(pattern, '$2 $1') console.log(ans); // world hello
後向引用 & 零寬斷言
簡單地說:從左向右,以分組的左括號爲標誌,第一個出現的分組的組號爲1,第二個爲2,以此類推。
複雜地說:分組0對應整個正則表達式實際上組號分配過程是要從左向右掃描兩遍的:第一遍只給未命名組分配,第二遍只給命名組分配--所以全部命名組的組號都大於未命名的組號。可使用(?:exp)這樣的語法來剝奪一個分組對組號分配的參與權.
若是咱們要找連續兩個同樣的字符,好比要找兩個連續的c,能夠這樣/c{2}/,若是要找兩個連續的單詞hello,能夠這樣/(hello){2}/,可是要在一個字符串中找連續兩個相同的任意單詞呢,好比一個字符串hellohellochinaworldworld,我要找的是hello和world,怎麼找?
這時候就要用後向引用。看具體例子:
var s = 'hellohellochinaworldworld'; var pattern = /(\w+)\1/g; var a = s.match(pattern); console.log(a); // ["hellohello", "worldworld"]
這裏的\1就表示和匹配模式中的第一個子表達式(分組)同樣的內容,\2表示和第二個子表達式(若是有的話)同樣的內容,\3 \4 以此類推。(也能夠本身命名,詳見參考文獻)
或許你以爲數組裏兩個hello兩個world太多了,我只要一個就夠了,就又要用到子表達式了。由於match方法裏是不能引用子表達式的值的,咱們回顧下哪些方法是能夠的?沒錯,exec和replace是能夠的!
exec方式:
var s = 'hellohellochinaworldworld'; var pattern = /(\w+)\1/g; var ans; do { ans = pattern.exec(s); console.log(ans); } while(ans !== null); // result // ["hellohello", "hello", index: 0, input: "hellohellochinaworldworld"] index.html:69 // ["worldworld", "world", index: 15, input: "hellohellochinaworldworld"] index.html:69 // null
若是輸出只要hello和world,console.log(ans[1])便可。
replace方式:
var s = 'hellohellochinaworldworld'; var pattern = /(\w+)\1/g; var ans = []; s.replace(pattern, function(a, b) { ans.push(b); }); console.log(ans); // ["hello", "world"]
若是要找連續n個相同的串,好比說要找出一個字符串中出現最多的字符:
String.prototype.getMost = function() { var a = this.split(''); a.sort(); var s = a.join(''); var pattern = /(\w)\1*/g; var a = s.match(pattern); a.sort(function(a, b) { return a.length < b.length; }); var letter = a[0][0]; var num = a[0].length; return letter + ': ' + num; } var s = 'aaabbbcccaaabbbcccccc'; console.log(s.getMost()); // c: 9
若是須要引用某個子表達式(分組),請認準後向引用!
別被名詞嚇壞了,其實解釋很簡單。
它們用於查找在某些內容(但並不包括這些內容)以後的東西,也就是說它們像\b,^,$那樣用於指定一個位置,這個位置應該知足必定的條件(即斷言)
零寬度正預測先行斷言,它斷言自身出現的位置的後面能匹配表達式exp。
// 獲取字符串中以ing結尾的單詞的前半部分 var s = 'I love dancing but he likes singing'; var pattern = /\b\w+(?=ing\b)/g; var ans = s.match(pattern); console.log(ans); // ["danc", "sing"]
零寬度負預測先行斷言,斷言此位置的後面不能匹配表達式exp
// 獲取第五位不是i的單詞的前四位 var s = 'I love dancing but he likes singing'; var pattern = /\b\w{4}(?!i)/g; var ans = s.match(pattern); console.log(ans); // ["love", "like"]
javascript正則只支持前瞻,不支持後瞻((?<=exp)和(?<!exp))。
關於零寬斷言的具體應用能夠參考綜合應用一節給字符串加千分符。
由於某些字符已經被正則表達式用掉了,好比. * ( ) / \ [],因此須要使用它們(做爲字符)時,須要用\轉義
var s = 'http://www.cnblogs.com/zichi/'; var pattern = /http:\/\/www\.cnblogs\.com\/zichi\//; var ans = pattern.exec(s); console.log(ans); // ["http://www.cnblogs.com/zichi/", index: 0, input: "http://www.cnblogs.com/zichi/"]
若是須要匹配abc裏的任意字母,能夠用[abc],可是若是不是單個字母那麼簡單,就要用到分支條件。
分支條件很簡單,就是用|表示符合其中任意一種規則。
var s = "I don't like you but I love you"; var pattern = /I.*(like|love).*you/g; var ans = s.match(pattern); console.log(ans); // ["I don't like you but I love you"]
答案執行了貪婪匹配,若是須要懶惰匹配,則:
var s = "I don't like you but I love you"; var pattern = /I.*?(like|love).*?you/g; var ans = s.match(pattern); console.log(ans); // ["I don't like you", "I love you"]
String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }; var s = ' hello world '; var ans = s.trim(); console.log(ans.length); // 12
String.prototype.getAns = function() { var pattern = /(?=((?!\b)\d{3})+$)/g; return this.replace(pattern, ','); } var s = '123456789'; console.log(s.getAns()); // 123,456,789
String.prototype.getMost = function() { var a = this.split(''); a.sort(); var s = a.join(''); var pattern = /(\w)\1*/g; var a = s.match(pattern); a.sort(function(a, b) { return a.length < b.length; }); var letter = a[0][0]; var num = a[0].length; return letter + ': ' + num; } var s = 'aaabbbcccaaabbbcccccc'; console.log(s.getMost()); // c: 9
出處:http://www.codeceo.com/article/javascript-reg-expression.html