javascript開發中正則表達式的使用技巧

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])方法,以某規則或字符串替換對應的字符串,返回替換後的字符串

發佈留言