一、前言
正則表達(dá)式,在平常的開發(fā)中也是司空見慣了,比如手機(jī)號、郵箱、密碼等規(guī)則校驗(yàn)都是需要用到正則。
二、理解正則需要做的事情
可以總結(jié)為下:
1、匹配啥? 2、匹配不是啥? 3、匹配多少次
1、匹配啥
這個(gè)比較好理解,比如像匹配字符a,那就直接寫
/a/,只要字符串某個(gè)位置是a就可以匹配上:
/a/.test('javascript') //true
匹配以a開頭的字符串 就加上元字符
^(開始位置標(biāo)識),/^a/:
/^a/.test('javascript') // 不是以a開頭 返回 false
/^a/.test('abc') //以a開頭 返回 true
匹配以a結(jié)尾的字符串,就加上元字符
$(結(jié)束位置標(biāo)識),```/a$/
/a$/.test('javascript') // 不是以a結(jié)尾返回false
/a$/.test('cba') // 以a結(jié)尾 返回 true
匹配字符a或b,可以把對應(yīng)的字符放入中括號里
/[ab]/,只要字符串包含a或者b就可以匹配上
/[ab]/.test('byte') // true
匹配字符串a(chǎn)bc或者xyz ```/abc|xyz/
/abc|xyz/.test('aabbxyz') // 本字符串包含xyz 所以返回true
①匹配啥前面的(前瞻)
exp1(?exp2):匹配exp2前面的exp1,匹配結(jié)果不包含exp2
比如要匹配字符串中的script前面的部分java,/java(?=script)/
/java(?=script)/.test('javascript,javaee,typescript') // 字符串中javascript符合規(guī)則 會返回 true
// 1、用exec方法來驗(yàn)證下面的匹配結(jié)果
/java(?=script)/.exec('javascript,javaee,typescript')
//2、得到匹配結(jié)果如下:
["java",index:0,input:"javascript,javaee,typescript",groups:undefined]
//3、會發(fā)現(xiàn)匹配到的是java,index是0,說明找到了的是JavaScript中的script前面的java
②匹配啥后面的(后顧)
(?<=exp2)exp1:匹配exp2后面的exp1,匹配結(jié)果不包含exp2
比如要匹配字符串中java后面的ee,/java(?<=ee)/
/(?<=java)ee/.test("javascript,javaee,typescript") //字符串中javaee符合規(guī)則 會返回ture
//1、用exec方法來驗(yàn)證下匹配的結(jié)果
/(?<=java)ee/.exec("javascript,javaee,typescript")
//2、得到匹配結(jié)果如下:
["ee", index: 15, input: "javascript,javaee,typescript", groups: undefined]
//3、會發(fā)現(xiàn)匹配到的是ee,index是15,說明找到了的是javaee中java后面的ee
匹配不是啥?
匹配不是啥就是取反,只要不是這些的都可以匹配,比如不相匹配字符a,正則寫法為
/[^a]/,是在中括號中加上元字符^```,這樣只要字符串滿足又不是這個(gè)集合里面的字符,都可以被匹配上:
/[^a]/.test('aaa') // 字符串全是a, 返回false
/[^a]/.test('abc') // 字符串不全是a,返回true
匹配不是以a開頭的跟之前匹配啥類似,加上
^,/^[^a]/
/^[^a]/.test('javascript') // 此字符串不是以a開頭 返回 true
/^[^a]/.test('abc') // 此字符串是以a開頭 返回false
匹配不是以a結(jié)束的,也跟之前匹配啥類似,加上元字符
$,/[^a]$/
/[^a]$/.test('javascript') // 此字符串不是以a結(jié)束 返回true
/^[^a]/.test('cba') // 此字符串以a結(jié)束 返回false
不匹配字符串a(chǎn)、b、c可以把對應(yīng)的字符串都放入到中括號中
/[^abc]/
/[^abc]$/.test('abccba') // 此字符串全部都不符合 返回 false
① 匹配后面不是啥的(負(fù)前瞻)
exp1(?!exp2):匹配后面不是exp2的exp1,匹配結(jié)果不包含exp2
比如要匹配字符串中后面不是script的java, /java(?!script)/:
/java(?!script)/.test("javascript,javaee,typescript") //字符串javaee符合規(guī)則 會返回ture
//1、用exec方法來驗(yàn)證下匹配的結(jié)果
/java(?!script)/.exec("javascript,javaee,typescript")
//2、得到匹配結(jié)果如下:
["java", index: 11, input: "javascript,javaee,typescript", groups: undefined]
//3、會發(fā)現(xiàn)匹配到的是java,index是11,說明找到了的是javaee中的java,因?yàn)檫@個(gè)java后面是ee
② 匹配前面不是啥的(負(fù)后顧)
(?<!exp2)exp1:匹配前面不是exp2的exp1,匹配結(jié)果不包含exp2
比如要匹配字符串中前面不是java的script,/(?<!java)script/:
/(?<!java)script/.test("javascript,javaee,typescript") //字符串中typescript符合規(guī)則 會返回ture
//1、用exec方法來驗(yàn)證下匹配的結(jié)果
/(?<!java)script/.exec("javascript,javaee,typescript")
//2、得到匹配結(jié)果如下:
["script", index: 22, input: "javascript,javaee,typescript", groups: undefined]
//3、會發(fā)現(xiàn)匹配到的是script,index是22,說明找到了的是typescript中type后面的script
③ 不匹配包含abc的字符串
這是一個(gè)比較特殊的匹配行為,如果只是寫成/[^abc]/的話,這只意味著字符串不能全是由a、b、c這三個(gè)組成的,跟需求不匹配。
那我們要從另外一個(gè)角度去分析,字符串的任意一個(gè)位置開始都不能連續(xù)出現(xiàn)abc,我們可以利用負(fù)前瞻的特性來匹配,然后一步一步來實(shí)現(xiàn)這個(gè)正則:
1、位置后面不能是abc,使用負(fù)前瞻匹配位置:/(?!abc)/
2、從開始到結(jié)束每個(gè)位置都要覆蓋到,添加開始結(jié)束標(biāo)記:/^(?!abc)/$
3、這個(gè)位置后面可以是其他的字符,用\w來表示:/^(?!abc)\w$/
4、滿足上面情況后的位置,可以連續(xù)出現(xiàn)多個(gè),用+來表示數(shù)量:/^((?!abc)\w)+$/
/^((?!abc)\w)+$/.test("cbacbac") //本字符串中不包含連續(xù)的abc,結(jié)果返回true
/^((?!abc)\w)+$/.test("cbacbabc") //本字符串中包含連續(xù)的abc,結(jié)果返回false
3、匹配多少次?
匹配一次可以什么都不用定義,比如匹配一個(gè)數(shù)字
/\d/,如果要匹配連續(xù)是三個(gè)數(shù)組最簡單的方式就是連續(xù)寫三次:/\d\d\d,這樣寫本身沒有問題,能正確匹配。
但是如果次數(shù)太多 或者次數(shù)不確定,肯定就有問題了,所以可以加上長度規(guī)則
*:匹配任意次
+:最低匹配一次
?:匹配1次或者0次
{m}:匹配m次
{m,}:最低匹配m次
{m,n}:最低匹配m次,最多匹配n次,m需要小于等于n
正則默認(rèn)是貪婪匹配,就是符合條件的會一直匹配,如果想阻止貪婪匹配,可以在長度規(guī)則后面加上一個(gè)?,比如
/\d{2,}/.exec('1234567890')
//得到匹配結(jié)果如下:會匹配到所有的數(shù)字:
["1234567890", index: 0, input: "1234567890", groups: undefined]
// 1、添加?,會阻止非貪婪匹配后
/\d{2,}?/.exec('1234567890')
//2、得到匹配結(jié)果如下,只會匹配2個(gè)數(shù)字:
["12", index: 0, input: "1234567890", groups: undefined]
① 使用分組
如果想匹配多次某個(gè)單詞如regregregregregreg時(shí)候怎么辦,我們看到reg連續(xù)出現(xiàn)了6次,如果傻傻的把6個(gè)reg寫在了正則表達(dá)式中肯定不合適,我們就可以利用分組來實(shí)現(xiàn),我們把reg放在括號里面,然后讓這個(gè)分組重復(fù)6次,/(reg){6}/:
/(reg){6}/.test("regregregregregreg") //匹配成功,返回true
不過這樣利用分組是有個(gè)前提,就是知道要匹配的字符串就是reg,然后重復(fù)這個(gè)分組。如果想匹配類似8899或者5522這種重疊類型的字符怎么辦呢?那我們可以把重疊的第一個(gè)放入分組,再通過
\n捕獲這個(gè)分組內(nèi)容來匹配下一個(gè):
/(\d)\1(\d)\2/.exec("2345566789")
//得到匹配結(jié)果如下,返回了5566,分組對應(yīng)的5、6也被返回
["5566", "5", "6", index: 3, input: "2345566789", groups: undefined]
② 分組捕獲
默認(rèn)的分組是可以被捕獲的,上面的\1、\2是在正則表達(dá)式內(nèi)部捕獲的分組。如果想在外部去捕獲分組匹配的數(shù)據(jù)可以使用RegExp.$1-$9來獲取。只要正則匹配了就會有。可以使用test、exec或者str的replace方法來獲取$1-$9。
使用test:
/([a-z]{2})(\d{2})/.test("xyz123")
RegExp.$1 //返回第一個(gè)分組表達(dá)式匹配到的內(nèi)容 yz
RegExp.$2 //返回第二個(gè)分組表達(dá)式匹配到的內(nèi)容 12
使用replace:
"xyz123".replace(/([a-z]{2})(\d{2})/,'$2$1')
//會返回結(jié)果:x12yz3,就是把第一個(gè)分組匹配到的內(nèi)容yz和第二個(gè)分組匹配到的內(nèi)容12互換了
③ 分組不捕獲
如果不想捕獲分組,只需要在分組內(nèi)加上?:就可以了
/([a-z]{2})(?:\d{2})/.test("xyz123")
RegExp.$1 //返回第一個(gè)分組表達(dá)式匹配到的內(nèi)容 yz
RegExp.$2 //分組未被捕獲 返回空字符串