正則的用法
const regex = /abc/g
const regex2 = new RegExp('abc', 'g')
regex 和 regex2的匹配內(nèi)容是一樣的,都是全局匹配abc字符串刻蟹,
只不過regex是用正則表達(dá)式字面量逗旁,而regex2是調(diào)用RegExp構(gòu)造函數(shù)寫法。
元字符
^ 匹配字符串的開始 /^a/ 表示匹配以a開始
$ 匹配字符串的結(jié)尾 /a$/ 表示匹配以a結(jié)尾
\d [0-9] 表示0-9的任意一位數(shù)字 /^\d/ 表示以一個(gè)數(shù)字開始
\D [^0-9] 表示除數(shù)字外的任意字符 /^\D/ 表示不能以數(shù)字開始
\w [0-9a-zA-Z_] 表示數(shù)字舆瘪、大小寫字母和下劃線
\W [^0-9a-zA-Z_] 表示非單詞字符
\s [\t\v\n\r\f]片效。表示空白符,包括空格英古、水平制表符淀衣、垂直制表符、換行符召调、回車符膨桥、換頁符
\S [^ \t\v\n\r\f] 非空白符
\b 匹配一個(gè)單詞邊界
\B 匹配非單詞邊界
. [^\n\r\u2028\u2029]。通配符唠叛,表示幾乎任意字符只嚣。換行符、回車符玻墅、行分隔符和段分隔符除外介牙。
要是想匹配字符串.需要轉(zhuǎn)譯\.
量詞
{m, n} 出現(xiàn)了m-n次
{m} 出現(xiàn)了m次
{m,} 出現(xiàn)了至少mci
{,n} 最多出現(xiàn)了n次
壮虫? 出現(xiàn)了0次或1次澳厢, 等價(jià)于{0,1}
+ 最少出現(xiàn)了1次,等價(jià)于{1,}
* 出現(xiàn)0次或多次,等價(jià)于{0,}
貪婪與惰性
貪婪就是盡可能多的匹配囚似,而惰性就是盡可能少的匹配
貪婪匹配寫法:量詞后面加個(gè)*
惰性匹配寫法:量詞后面加個(gè)剩拢?
/.*bbb/g.exec('abbbaabbbaaabbb1234') // abbbaabbbaaabbb
/.*?bbb/g.exec('abbbaabbbaaabbb1234') // abbb
貪婪模式用于匹配優(yōu)先量詞修飾的子表達(dá)式
惰性模式用于匹配忽略優(yōu)先量詞修飾子表達(dá)式
分組
正則中一對()即為一個(gè)分組
/(abx).*/.test('abxsss') 其中(abx) 就是一個(gè)分組
可使用構(gòu)造函數(shù)的全局屬性9來獲取
/(abx).*/.exec('abxsss')
console.log(RegExp.$1) // abx
console.log(RegExp.$_) // abxsss
只能表示到9, 如果分組超過了九組饶唤,那就沒法表示了
反向引用
/\d{4}(-|\/|\.)\d{2}\1\d{2}/
注意里面的\1徐伐,表示的引用之前的那個(gè)分組(-|\/|\.)。
不管它匹配到什么(比如-)募狂,\1都匹配那個(gè)同樣的具體某個(gè)字符办素。
我們知道了\1的含義后,那么\2和\3的概念也就理解了祸穷,即分別指代第二個(gè)和第三個(gè)分組性穿。
這里的分組只是在此之前的分組,在該反向引用之后的無法表示雷滚。
/\d{4}(-|\/|\.)\d{2}\2(\d{2})/
這里不能用\2來引用(\d{2})分組需曾,這里只是當(dāng)作匹配\2去匹配,而不是當(dāng)作分組的引用
具名分組
/(\d{4}(-|\/|\.))\d{2}\2\d{2}/
這里的第二個(gè)分組應(yīng)該是(-|\/|\.)
那/^((\d)(\d(\d)))$/的分組又是怎么分的呢?
對于過多括號嵌套情況呆万,分清分組比較容易出錯(cuò)
括號嵌套的分組商源,應(yīng)該從第一個(gè)(往里面數(shù),每遇到一個(gè)(就是一個(gè)新的分組
具名分組就很好的解決了這個(gè)問題
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
這里就是用到了具名分組
可以通過\k<month>引用具體是哪個(gè)分組
/(?<year>\d{4})-(?<month>\d{2})-\k<month>/
具名分組結(jié)果會(huì)放在group屬性里面
非捕獲分組
也可以通過非捕獲分組來降低分組的復(fù)雜度谋减。非捕獲分組是指不會(huì)將(?:)中的正則化為一個(gè)分組牡彻。
/^(?:(?:\d)(\d(\d)))\2$/
這里\2引用的分組是(\d)
零寬斷言(環(huán)視)和負(fù)零寬斷言
/z(?=x)y/ 表示z后面緊跟著的是x,但是不匹配x
/z(?!x)y/ 表示z后面緊跟著的不是x逃顶,但是不匹配x
/z(?<=x)y/ 表示y前面緊跟著的是x讨便,但是不匹配x
/z(?<!x)y/ 表示y前面緊跟著的不是x,但是不匹配x
修飾符
1. g → global 全局搜索
2. i → ignoreCase 忽略大小寫以政,大小寫不敏感
3. m → multiline 換行
4. y → sticky “粘連”修飾符 后一次匹配都從上一次匹配成功的下一個(gè)位置開始
5. u → unicode Unicode 字符表示法
lastIndex
是正則表達(dá)式的一個(gè)可讀可寫的整型屬性霸褒,用來指定下一次匹配的起始索引。
只有正則表達(dá)式使用了表示全局檢索的 "g" 標(biāo)志時(shí)盈蛮,該屬性才會(huì)起作用废菱。此時(shí)應(yīng)用下面的規(guī)則:
如果 lastIndex 大于字符串的長度,則 regexp.test 和 regexp.exec 將會(huì)匹配失敗抖誉,然后 lastIndex 被設(shè)置為 0殊轴。
如果 lastIndex 等于字符串的長度,且該正則表達(dá)式匹配空字符串袒炉,則該正則表達(dá)式匹配從 lastIndex 開始的字符串旁理。(then the regular expression matches input starting at lastIndex.)
如果 lastIndex 等于字符串的長度,且該正則表達(dá)式不匹配空字符串 我磁,則該正則表達(dá)式不匹配字符串孽文,lastIndex 被設(shè)置為 0.。
否則夺艰,lastIndex 被設(shè)置為緊隨最近一次成功匹配的下一個(gè)位置芋哭。
練習(xí)
1.檢測是否滿足
2016-06-12
2016/06/12
2016.06.12
這三種格式
/\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/.test('2012/12/13')
這樣寫有一個(gè)問題,那就是
/\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/.test('2012/12-13') 也是true
所以這里就得用到分組引用了
/\d{4}(-|\/|\.)\d{2}\1\d{2}/.test('2012/12-13') false
/\d{4}(-|\/|\.)\d{2}\1\d{2}/.test('2012/12/13') true
這里的\1指的是第一個(gè)分組匹配到了什么郁副,這里就是什么
2.將 2016/12/04 改為 12/04/2016
傳統(tǒng)做法可能是需要先以'/'分割字符串减牺,然后在就行字符串拼接
現(xiàn)在可以這樣寫
'2016/12/04'.replace(/(\d{4})\/(\d{2})\/(\d{2})/, '$2/$3/$1')
或者
'2016/12/04'.replace(/(\d{4})\/(\d{2})\/(\d{2})/, function(...arg) {
return arg[2]+'/' + arg[3]+'/' + arg[1]
})
let result = /(?<year>\d{4})\/(?<month>\d{2})\/(?<day>\d{2})/.exec('2016/12/04')
console.log(result)
// 0: "2016/12/04"
// 1: "2016"
// 2: "12"
// 3: "04"
// groups:
// day: "04"
// month: "12"
// year: "2016"
// index: 0
// input: "2016/12/04"
3.可以正確篩選以下規(guī)則
'x=5' 5
'abcx=5' 5
'abc x=5' 5
'x=abc' null
str.match(/(?<=x=)\d+/)
4.可以正確篩選以下規(guī)則
'x=5' 5
'abcx=5' null
'abc x=5' 5
'x=abc' null
這個(gè)和上面的區(qū)別就在于x=之前是不是一個(gè)邊界
str.match(/(?<=\bx=)\d+/)
不可以用一下的正則匹配
str.match(/(?<=\s+x=)\d+/)
因?yàn)檫@樣的話'x=5'就不匹配了
5.可以正確篩選以下規(guī)則
'one "two three" four five six "seven eight" nine'
to
'"two three" four five six "seven eight"'
str.match(/".*"/g)
6.可以正確篩選以下規(guī)則
'one "two three" four five six "seven eight" nine'
to
['"two three"', '"seven eight"']
str.match(/".*?"/g)
這里和上面的區(qū)別就在于一個(gè)是貪婪匹配而這個(gè)是惰性匹配
7.可以正確篩選以下規(guī)則
'@@whatever@@@@whatever2@@'
to
'<blink>whatever</blink><blink>whatever2</blink>'
str.replace(/(@@)(.*?)(@@)/g, function(...arg) {
return '<blink>'+ arg[2]+'</blink>'
})
這里不能簡單的將'@@'替換成'<blink>',因?yàn)?@@'必須是成對出現(xiàn)的
8.可以正確篩選以下規(guī)則
var text = "First line\nsecond line";
var regex = /(\S+) line\n?/y;
var match = regex.exec(text);
match[1]; // "First"
var match2 = regex.exec(text);
match2[1]// "Second"
var match3 = regex.exec(text);
match3 === null //"true"
這里是開啟粘滯匹配的一個(gè)事例
9.測試以下代碼
var re=/^\w$/g
re.test('a') true
re.test('a') false
re.test('a') true
re.test('a') false
re.test('a') true
re.test('a') false
re.test('a') true
re.test('a') false
...
為什么會(huì)出現(xiàn)這種情況呢?
這里就涉及到了lastIndex了存谎,
var re=/^\w$/g
re.lastIndex = 0
re.test('a') true
這里正則匹配完成后re.lastIndex = 1
re.test('a') false
因?yàn)閞e.lastIndex = 1了拔疚,所以這里的re.test就會(huì)失效,當(dāng)然re.exec也會(huì)失效既荚。
可以理解為這時(shí)正則是從1這個(gè)位置去匹配的稚失,所以匹配不到任何東西.只會(huì)就會(huì)再次把lastIndex改為0
re.lastIndex = 0
re.test('a') true
又重新從頭開始匹配了,所以這里又再次為true了
結(jié)尾
本文并沒有舉例傳統(tǒng)的一下正則固以,如郵箱格式墩虹,手機(jī)號碼格式等嘱巾,因?yàn)檫@些正則可以搜到很多。本文主要是用到了一下稍微高階一點(diǎn)的正則方法诫钓。古人云:用好了正則旬昭,可以幫我們省下5000行代碼。