本文是lhyt本人原創(chuàng),希望用通俗易懂的方法來理解一些細節(jié)和難點。轉載時請注明出處。文章最早出現于本人github
0.前言
本文主要介紹了捕獲和非捕獲的概念,并舉了一些例子,這些都是正則表達式在js中進階的一些用法。后面有彩蛋哦
1.捕獲
1.1RegExp對象的相關屬性
一般用()括住的就是捕獲組,而且類似于算術中的括號,從左到右,逐層去括號。比如存在(A)((B)C)這種,他捕獲到的將會是(A)((B)C)、(B)、((B)C),并在內存中存放,可以通過RegExp對象的$屬性來訪問到。
/(1((2)3))/.test('123')
RegExp.$1 //123
RegExp.$2 //2
RegExp.$3 //23
/(((1)2)3)/.test('123')
RegExp.$1 //123
RegExp.$2 //12
RegExp.$3 //1
這個順序,按左括號的順序來算的,第幾個(就表示第幾個$符號屬性,一般從1開始,最多$9
還有一些舊的RegExp長屬性名,在高級程序設計108頁里面

簡寫的話還是有很多不兼容的問題的,最好寫全稱
1.2數字的反向引用
有的人就問,用正則怎么匹配AABB類型的詞語?比如高高興興、亮晶晶這些。在正則里面反斜杠+數字就可以做到,表示重復第n個捕獲組的內容,這個n和上面$后面的數字同理:
/(.)\1(.)\2/.test('高高興興') //TRUE,第一個和第二個相同,第三四個相同
/(.)(.)\2/.test('亮晶晶') // TRUE ,后面兩個相同
2.非捕獲
以 (?) 開頭的組是非捕獲組,它不捕獲文本 ,也不針對組合計進行各種操作,不將匹配到的字符存儲到內存中,從而節(jié)省內存。也就是上面所講的$屬性他都不會具有。一般用于只需要檢測結果的情況。
(?:a)非捕獲一個a
/(?:a)1(?:b)/.test('a1b') //true
RegExp.$1 //''
var reg = /(?:\d{4})-(\d{2})-(\d{2})/
var date = '2018-01-02'
reg.test(date)
RegExp.$1 // 01
RegExp.$2 // 02
2.1斷言
也有人叫前瞻,顧名思義,就是往前面(右邊)看,看看是不是某個東西。
(?=x) 匹配后面是x的數據 :
/i am (?=a)/.test('i am a') //你右邊是a
(?!x) 匹配后面不是x的數據
/i am (?!a)/.test('i am b') //你右邊不是a
2.2篩選
(?!B)[A-Z]:在大寫字母集合中,除去B
/(?!B)[A-Z]/.test('A') //true
/(?!B)[A-Z]/.test('B') //false
3.匹配模式
3.1惰性匹配和貪婪模式
*? 重復0次或更多次
+? 重復一次或更多次
?? 重復0次或一次
{n,}? 重復n次或更多次
{n,m}? 重復n到m次
以上所有的匹配都是盡可能的少重復,只要滿足條件就行了,不繼續(xù)匹配了,在某個程度來說也是性能優(yōu)化的方法之一。
那么貪婪模式就是沒有做了上面的措施的都屬于貪婪模式,比如正則元字符、量詞單獨出現的情況。
對于字符串'abbba'使用/ab*/g和/ab*? /g
貪婪模式:ab* 結果:abbb 和 a,第一次找到了a,繼續(xù)找發(fā)現后面接幾個b也是符合的,直到發(fā)現了第二個a才停止,再找到第二個a
惰性匹配:ab*? 結果:a 和 a,第一次找到了a,*的要求是不需要b也可以,所以停止,接著又找到第二個a
彩蛋:
檢測一個數是否是質數的方法
相信大家都見過一個很強大的函數,一行代碼判斷出一個數是不是質數:
function isPrime(n){
return n<2?false:!/^(11+?)\1+$/.test(Array(n+1).join('1'))
}
看上去好像很牛逼,容我細細道來:
首先最小的質數是2,所以先判斷是否小于2
如果大于2,先創(chuàng)建一個長度是n的字符串,里面鋪滿了1。Array(n+1)創(chuàng)建n+1個空位(undefined),再用1作為分隔符分開轉化為字符串,所以就得到一個長度為n的字符串,全是1組成
^11+?怎么理解
表示以1開頭,后面惰性匹配多個1(1個或者無窮個)
\1+$怎么理解
表示重復^11+?這段匹配到的內容
合起來怎么理解
神奇的地方來了,首先,惰性匹配的是一個1,也就是11,后面重復11的整數次,也就是重復2次4次6次...等等,如果剛剛好匹配到了,說明這個數能被整除,說明他不是質數。如果后面的字符串不能構成2的整數倍個11,那么第一輪惰性匹配失敗。
接著第二輪惰性匹配,匹配11,也就是前面捕獲的是111,那么后面就開始重復111的整數倍,如果剛剛好能匹配完,說明不是質數
接著第三輪,匹配111,捕獲到1111,后面重復1111的整數倍
...
直到不能再匹配,說明這個數就是質數。
其實,里面相當于循環(huán)
for(var i = 2;i<n;i++){
if(n%i==0){return false}
}
return true
正則的強大,真的是法力無邊。jQuery作者正則玩得飛起,號稱世界上最強的選擇器sizzle,就是強大正則做出來的
原文來自lhyt的github