javascript開發中正則表達式的使用技巧。
javascript的正則表達式不支持以下特性:
1.匹配字符串開頭和結尾的\A和\Z錨(但支持^、$插入符號做開頭和結尾)
2.向後查找
3.並集和交集類
4.原子組
5.Unicode支持(單個字符除外,如\uFFFF)
6.命名的捕獲組(子表達式,後面會詳細解析)
7.s(single,單行匹配模式)和x(free-spacing,無間隔匹配模式)
8.條件匹配–(這是個好東西啊…然而js沒有,555~)
9.正則表達式註釋
這裡,解析下原子組-語法->(?>group),根據google查詢到的資料:以下表達式a(?bc|b)c會匹配abcc,但不匹配abc,然後原子組匹配的時候會自動丟棄回溯引用位置,也就是說無法將使用回溯引用。具體怎麼用請另行goole,畢竟js裡不支持這個特性,So mind my business?英語好且可以翻墻的各位->傳送門
what(正則表達式是什麼)
正則表達式是一門利用特殊字符定義匹配規則的技術,主要是用來處理字符串的搜索和替換,字符串在編程語言裡是經常出現的基本數據類型,難免會涉及到字符串的處理,一般字符串對象內置的字符串處理方法,但是增加代碼量是一大弊端。這時候,正則就出場瞭,正則表達式以極短的匹配字符,可以滿足任意的字符串操作。
How(javascript中的正則表達式使用)
首先,在javascript中,創建正則表達式的的方式有兩種:
//第一種方式(繼承Perl的語法) var reg1 = /\w+/g; //第二種方式,創建RegExp對象 var reg2 = new RegExp("\\w+","g");
有些人可能會對“\w+”,“g”…這些東西無解,看不懂的上面的正則表達式並沒有關系,下文會做詳細的解析。
正則表達式的元字符
元字符
元字符 | 含義 |
---|---|
\ | 一般用來做元字符的轉義操作,但其本身也是元字符 |
. | 匹配單個任意字符,除瞭換行符和結束符 |
\d | 匹配字符串中的數字(digit,數字) |
\D | 匹配字符串中的非數字,即\d的補集 |
\w | 匹配字符串中的單詞(word,單詞。字母、數字、下劃線) |
\W | 匹配字符串中的非單詞部分,\w的補集 |
\s | 匹配字符串中的空格(space,空格:包括普通空格、制表符空格以及換行符空格) |
\S | 匹配字符串中的非空格部分,\s的補集 |
\b | 匹配字符串中的單詞邊界(boundary,邊界) |
\B | 匹配字符串中的非單詞邊界,\b的補集 |
\n | 匹配字符串中的換行符 |
\f | 匹配字符串中的換頁符 |
\r | 匹配字符串中的回車符 |
\t | 匹配字符串中的制表符:tab鍵 |
\v | 匹配字符串中的垂直制表符 |
\xxx | 查找以八進制數 xxx 規定的字符 |
\xdd | 查找以十六進制數 dd 規定的字符 |
\uxxxx | 查找以十六進制數 xxxx 規定的 Unicode 字符 |
註意:由於元字符在正則表達式裡具有特殊含義,所以在匹配的文本裡如果包含有元字符的需用\進行轉義。同等的,使用RegExp實例化的兩個參數是字符串,所以含有元字符也就行轉義。如:\轉義後是\\、\\轉義後是\\\\
區間表達式
區間表達式 | 含義 |
---|---|
[0-9] | 匹配0至9的數字,等同於\d |
[a-z] | 匹配小寫字母a至z |
[A-Z] | 匹配大寫字母A至Z |
[^0-9] | 匹配0至9的數字以外的字符串,等同於\D |
(red|blue|green) | 匹配字符串red/blue/green任意一個 |
舉個栗子
//測試字符 var str = "there are 4 cats at my home"; //正則表達式 var reg = /\b\w+\b/g; reg.exec(str);//["there", index: 0, input: "there are 4 cats at my home"] str.match(reg);//["there","are","4","cats","at","my","home"]
註:這裡exec()和match()方法返回的結果是有點類似的,但是需要註意的是前者是RegExp對象的方法,後者是String對象的方法。其兩個方法的主要區別在於exec()可以每次匹配一項,可以使用循環進行逐個匹配,For example:
//測試字符 var str = "there are 4 cats at my home"; //正則表達式 var reg = /\b\w+\b/g; var result; while((result = reg.exec(str))!=null){ console.log(result); console.log(reg.lastIndex);//lastIndex屬性下面會做解釋 }
正則表達式修飾符的匹配類型
修飾符 | 匹配模式 |
---|---|
g | 全局匹配 |
i | 忽略大小寫匹配 |
m | 多行匹配 |
使用栗子
//匹配所有的單詞 var str = "hello world"; //Perl語法 var reg = /\w+/gi; //RegExp對象實例化 var regexp = new RegExp("\\w+","gi");
正則表達式的貪婪匹配和懶惰匹配
量詞 | 含義 |
---|---|
+ | 匹配至少一個 |
? | 匹配零個或一個 |
* | 匹配零個或多個 |
{n} | 匹配n個 |
{n,m} | 匹配n至m個 |
{n,} | 匹配n個或n個以上 |
貪婪匹配和懶惰匹配都是與量詞有關的,所以上面先列出正則表達式的量詞
貪婪匹配的栗子
//首先指出上面屬於貪婪型的量詞有:+、*、{n,} //下面我們來匹配一個h3標簽內容 var str = "
this is an example
this is an example too
"; var reg = /
.*<\/h3>/g; str.match(reg);
註:相信很多人覺得上面的匹配沒啥毛病,Perfect!
蛋四,它結果是怎樣呢…(不相信的可以親測)
匹配的結果是
this is an example
this is an example too
Excuse Me?為啥會這樣呢?:(
這就是貪婪匹配的後果啊,所謂貪婪的欲望是沒有盡頭的,所以貪婪型匹配就是在匹配條件規則下盡可能的吞噬匹配的字符串,因為有兩個結束標簽,它當然是匹配後一個啦!
再來一個栗子
//下面我們來匹配一個h3標簽內容agian... var str = "
this is an example
this is an example too
"; //註意修改後的正則表達式與上一個例子有什麼區別!!! var reg = /
.*?<\/h3>/g; str.match(reg); //["
this is an example
","
this is an example too
"];
這次匹配得到的就是我們想要的結果瞭,群眾的眼睛是雪亮的,上面的正則表達式的區別是多瞭這貨兒——?,沒錯!.*到.*?的轉變就起到瞭翻天覆地的變化,修改後的正則明顯沒有這麼貪婪瞭,Bingo!這個不貪婪的正則就是懶惰型匹配。
凡是貪婪型匹配都可以通過增加?來使它變為懶惰型匹配
子表達式(捕獲組)
子表達式是什麼鬼?別急,所謂的子表達式就是…子表達式(一陣扔鞋~)
咳咳,下面我就來一本正經的說下子表達式是個什麼東東,照舊,舉個栗子:
還是這個正則表達式/(<(h3)>)(.*?)(<\/h3>)/g(你丫的沒栗子啊,整天嚼同一粒栗子),還真沒有~咬我啊。其實呢栗子舉到好,調完bug回傢早嘛
/(<(h3)>)(.*?)(<\/h3>)/g這個栗子呢已經包含瞭子表達式的終極奧義,吶!括號裡的就是子表達式,明顯有4個子表達式:(<(h3)>),(h3),(.*?),(<\/h3>),這裡子表達式依次可以用RegExp.$1,RegExp.$2,RegExp.$3,RegExp.$4來獲得引用,或許有人會疑問,第二個子表達式,javascript正則的子表達式明顯是以左括號(出現的順序來界定的。
栗子+1
var str = "
this is an example
"; var reg = /(<(h3)>)(.*?)(<\/h3>)/g; reg.exec(str); console.log(RegExp.$1)//
console.log(RegExp.$2)//h3 console.log(RegExp.$3)//the is a example console.log(RegExp.$4)//
由子表達式引出的補充
回溯引用
閑話少說,上需求:使用正則匹配任意的標題標簽及內容
我美美地寫瞭個栗子:
var reg = /<[Hh][1-6]>.*?<\/[Hh][1-6]>/g; console.log("
this is an example
")//匹配成功 console.log("
this is an example too
")//匹配成功 console.log("
this is an example too too
")//匹配成功 //重點來瞭 console.log("
this is an example too…
")//匹配成功
明顯,最後一個匹配的字符串是不合法的閉合標簽不一致啊,我們想排除這種不合法情況,就應該把正則表達式改為這樣:
var reg = /<[Hh]([1-6])>.*?<\/[Hh]\1/g;
解析:上面的表達式就是巧妙運用瞭子表達式的效果,\1就是回引用瞭前面的子表達式([1-6]),對的,\1,\2…就是引用第一個至第n個子表達式的意思。回溯引用很有趣吧!
向前查找匹配/負向前查找匹配
符號 | 含義 |
---|---|
^ | 定義匹配的開頭 |
$ | 定義匹配的結尾 |
?=n | 匹配字符串後面緊接字符n的字符串,即向前查找匹配 |
?!n | 匹配字符串後面不緊接字符n的字符串,即負向前查找匹配 |
向前查找
需求:匹配下面單詞表裡面所有具有過去式的單詞
watched moved go eating run
噼裡啪啦,熟練打出以下表達式:
var reg = /\b\w+ed\b/g;
不用想瞭,上面的表達式是可以滴。蛋四,我想用向前查找的方式實現,該怎麼寫呢?該這樣:
var reg = /\b\w+(?=ed)\b/g;
這還不足以體現向前查找的威力,如果我立刻讓你寫出匹配非過去式的單詞,又該怎麼寫正則表達式呢?答案昭然若揭…(tips:負向前查找)
var reg = /\b\w+(?!ed)\b/g;
是的,正則就是這麼diao,不用懷疑。哈哈…
RegExp對象解析
RegExp對象是javacript內置的基本對象之一,下面我們來看一下RegExp對象的的屬性和方法:
RegExp的實例屬性
屬性名 | 含義 |
---|---|
global | 佈爾類型值,如果使用瞭全局匹配模式則返回true,反之返回false |
ignore | 佈爾類型值,如果使用瞭忽略大小寫匹配模式則返回true,反之返回false |
multiline | 佈爾類型值,如果,如果使用多行匹配模式則返回true,反之返回false |
lastIndex | 整型數據,表示下一個匹配項的字符開始位置,從0開始索引 |
source | 返回正則表達式的字符串表示 |
RegExp的構造函數屬性
長屬性名 | 短屬性名 | 含義 |
---|---|---|
input | $_ | 返回最近一次匹配的全部字符串文本 |
lastMatch | $& | 返回最近一次匹配的字符串 |
lastParen | $+ | 返回最近一次匹配的捕獲組,即子表達式 |
leftContext | $` | 返回匹配的字符串的左邊的文本內容 |
rightContext | $’ | 返回匹配的字符串的右邊的文本內容 |
multiline | $* | 佈爾類型值,如果,如果使用多行匹配模式則返回true,反之返回false |
大大的栗子again
var str = "this has been a short summer"; var reg = /(.)hort/g; str.match(reg); document.write(RegExp["$_"]);//"this has been a short summer" document.write(RegExp["$&"]);//"short" document.write(RegExp["$`"]);//"this has been a " document.write(RegExp["$'"]);//" summer" document.write(RegExp["$+"]);//"s" document.write(RegExp["$*"]);//false/undefined(chrome 53.0)
Advise:個人建議使用這些屬性時候,使用長屬性名會更佳,因為這些名字能夠見名知意,在協同開發裡能夠起到自文檔的優秀實踐效果
Lastly,總結一下,正則表達式能在javascript的哪些方法使用:
RegExp對象的方法
exec([string])方法,返回第一個匹配項含有正則屬性數組 test([string])方法,返回佈爾值,true成功匹配,false失敗 compilie([regex])方法,重新編譯新的規則,貌似較少使用
String對象的方法
match([string|regex])方法,返回一個含有所有匹配項的數組 search([string|regex])方法,返回匹配項的開始位置索引值,匹配失敗返回-1 split([string|regex])方法,以某規則或字符串切割字符串,返回切割後字符串的數組 replace([string|regex],[string|regex])方法,以某規則或字符串替換對應的字符串,返回替換後的字符串