關於JS的正則表達式

原文來自個人github

0.前言

本文主要介紹了捕獲和非捕獲的概念,並舉了一些例子,這些都是正則表達式在js中進階的一些用法。後面有彩蛋哦javascript

1.捕獲

1.1RegExp對象的相關屬性

通常用()括住的就是捕獲組,並且相似於算術中的括號,從左到右,逐層去括號。好比存在(A)((B)C)這種,他捕獲到的將會是(A)((B)C)、(B)、((B)C),並在內存中存放,能夠經過RegExp對象的$屬性來訪問到。java

/(1((2)3))/.test('123')
RegExp.$1 //123
RegExp.$2 //23
RegExp.$3 //2
複製代碼
/(((1)2)3)/.test('123')
RegExp.$1 //123
RegExp.$2 //12
RegExp.$3 //1
複製代碼

這個順序,按左括號的順序來算的,第幾個就表示第幾個$符號屬性,通常從1開始,最多$9git

還有一些舊的RegExp長屬性名,在高級程序設計108頁裏面 github

111

因而,咱們常常有一個這樣的需求,將一個這樣子的字符串轉爲數組: "[a,[b],c]",我知道不少人確定說JSON.parse,恭喜,答對了。正則表達式

而後控制檯給你的的獎勵是: Uncaught SyntaxError: Unexpected token a數組

在這裏轉過去的不是字符串abc,而是變量abc,因此就直接報錯:Unexpected token a in JSON at position 1,想要parse,那麼這個字符串應該是這樣子"['a',['b'],'c']",這時候,咱們能夠用正則把他們換掉: "[a,[b],c]".replace(/\w+/g,"'$&'")性能優化

上面高程都說了$&匹配的是最近匹配的結果,咱們把匹配到的字串變成被兩個引號包圍的字符串,此次在parse就能正經常使用了。函數

另外,簡寫的話仍是有不少不兼容的問題的,最好寫全稱性能

1.2數字的反向引用

有的人就問,用正則怎麼匹配AABB類型的詞語?好比高高興興、亮晶晶這些。在正則裏面反斜槓+數字就能夠作到,表示重複第n個捕獲組的內容,這個n和上面$後面的數字同理:優化

/(.)\1(.)\2/.test('高高興興') //TRUE,第一個和第二個相同,第三四個相同
/(.)(.)\2/.test('亮晶晶')  // TRUE ,後面兩個相同
複製代碼

1.3 replace

replace第二個參數還能夠是一個函數,他的參數是matches,...catches,index。便是匹配結果,捕獲組,匹配位置,準確來講,第一個參數是匹配結果,最後一個參數是匹配位置,中間全部的參數都是捕獲組。 因而對於一個常見的小需求:讓字符串的連續字符變成一個 'aaaabbbbccc' =>'abc'

咱們能夠這樣子寫

'aaaabbbbccc' .replace(/(\w)\1+/g,function(a){
    return a[0]
})

//固然還能夠這樣子
'aaaabbbbccc' .replace(/(\w)\1+/g,'$1')

//還能夠手動設置
'aaaabbbbccc' .replace(/(\w)\1+/g,function(a){
    return a
}(1))//111
複製代碼

2.非捕獲

以 (?) 開頭的組是非捕獲組,它不捕獲文本 ,也不針對組合計進行各類操做,不將匹配到的字符存儲到內存中,從而節省內存。也就是上面所講的$屬性他都不會具備。通常用於只須要檢測結果的狀況。 (?: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次

以上全部的匹配都是儘量的少重複,只要知足條件就好了,不繼續匹配了,在某個程度來講也是性能優化的方法之一。 那麼貪婪模式就是沒有作了上面的措施的都屬於貪婪模式,好比正則元字符、量詞單獨出現的狀況。

對於字符串'abbba'使用/ab*/g和/ab*? /g 貪婪模式:ab* 結果:abbb 和 a,第一次找到了a,繼續找發現後面接幾個b也是符合的,直到發現了第二個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,先建立一個長度是n的字符串,裏面鋪滿了1。Array(n+1)建立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的整數倍 ... 直到不能再匹配,說明這個數就是質數。 其實,裏面至關於循環
for(var i = 2;i<n;i++){
if(n%i==0){return false}
}
return true
複製代碼

正則的強大,真的是法力無邊。jQuery做者的正則,號稱世界上最強的選擇器sizzle,就是強大正則作出來的(晚點再更新sizzle解讀)

相關文章
相關標籤/搜索