正則表達(dá)式從原理到實(shí)戰(zhàn)全面學(xué)習(xí)小結(jié)
正則表達(dá)式,名字聽上去就沒有吸引力,我發(fā)現(xiàn)很多前端對(duì)正則表達(dá)式了解不深,甚至有些懼怕,每次能夠運(yùn)行全憑運(yùn)氣,更有甚者完全靠復(fù)制粘貼。
正則表達(dá)式其實(shí)并不難,語(yǔ)法就那么多,而且一旦掌握在某些時(shí)候能夠給解決問題提供捷徑,更重要的是面試可能會(huì)被問到,要是不會(huì)那就尷尬了。
本文全面介紹正則表達(dá)式的語(yǔ)法知識(shí),全面介紹JavaScript中正則表達(dá)式的API,通過實(shí)戰(zhàn),希望能夠幫助大家全面學(xué)習(xí),并啃下前端的難題。
正則是啥?
下面是我對(duì)正則的理解:
正則就是用有限的符號(hào),表達(dá)無限的序列,殆已!
正則表達(dá)式的語(yǔ)法一般如下(js),兩條斜線中間是正則主體,這部分可以有很多字符組成;i部分是修飾符,i的意思表示忽略大小寫
/^abc/i
正則定義了很多特殊意義的字符,有名詞,量詞,謂詞等,下面逐一介紹
簡(jiǎn)單字符
沒有特殊意義的字符都是簡(jiǎn)單字符,簡(jiǎn)單字符就代表自身,絕大部分字符都是簡(jiǎn)單字符,舉個(gè)例子
/abc/ // 匹配 abc /123/ // 匹配 123 /-_-/ // 匹配 -_- /海鏡/ // 匹配 海鏡
轉(zhuǎn)義字符
\是轉(zhuǎn)義字符,其后面的字符會(huì)代表不同的意思,轉(zhuǎn)義字符主要有三個(gè)作用:
第一種,是為了匹配不方便顯示的特殊字符,比如換行,tab符號(hào)等
第二種,正則中預(yù)先定義了一些代表特殊意義的字符,比如\w等
第三種,在正則中某些字符有特殊含義(比如下面說到的),轉(zhuǎn)義字符可以讓其顯示自身的含義
下面是常用轉(zhuǎn)義字符列表:
| \n | 匹配換行符 |
| \r | 匹配回車符 |
| \t | 匹配制表符,也就是tab鍵 |
| \v | 匹配垂直制表符 |
| \x20 | 20是2位16進(jìn)制數(shù)字,代表對(duì)應(yīng)的字符 |
| \u002B | 002B是4位16進(jìn)制數(shù)字,代表對(duì)應(yīng)的字符 |
| \u002B | 002B是4位16進(jìn)制數(shù)字,代表對(duì)應(yīng)的字符 |
| \w | 匹配任何一個(gè)字母或者數(shù)字或者下劃線 |
| \W | 匹配任何一個(gè)字母或者數(shù)字或者下劃線以外的字符 |
| \s | 匹配空白字符,如空格,tab等 |
| \S | 匹配非空白字符 |
| \d | 匹配數(shù)字字符,0~9 |
| \D | 匹配非數(shù)字字符 |
| \b | 匹配單詞的邊界 |
| \B | 匹配非單詞邊界 |
| \\ | 匹配\本身 |
字符集和
有時(shí)我們需要匹配一類字符,字符集可以實(shí)現(xiàn)這個(gè)功能,字符集的語(yǔ)法用[``]分隔,下面的代碼能夠匹配a或b或c
[abc]
如果要表示字符很多,可以使用-表示一個(gè)范圍內(nèi)的字符,下面兩個(gè)功能相同
[0123456789] [0-9]
在前面添加^,可表示非的意思,下面的代碼能夠匹配a``b``c之外的任意字符
[^abc]
其實(shí)正則還內(nèi)置了一些字符集,在上面的轉(zhuǎn)義字符有提到,下面給出內(nèi)置字符集對(duì)應(yīng)的自定義字符集
- . 匹配除了換行符(\n)以外的任意一個(gè)字符 = [^\n]
- \w = [0-9a-zA-Z_]
- \W = [^0-9a-zA-Z_]
- \s = [ \t\n\v]
- \S = [^ \t\n\v]
- \d = [0-9]
- \D = [^0-9]
量詞
如果我們有三個(gè)蘋果,我們可以說自己有個(gè)3個(gè)蘋果,也可以說有一個(gè)蘋果,一個(gè)蘋果,一個(gè)蘋果,每種語(yǔ)言都有量詞的概念
如果需要匹配多次某個(gè)字符,正則也提供了量詞的功能,正則中的量詞有多個(gè),如?、+、*、{n}、{m,n}、{m,}
{n}匹配n次,比如a{2},匹配aa
{m, n}匹配m-n次,優(yōu)先匹配n次,比如a{1,3},可以匹配aaa、aa、a
{m,}匹配m-∞次,優(yōu)先匹配∞次,比如a{1,},可以匹配aaaa...
?匹配0次或1次,優(yōu)先匹配1次,相當(dāng)于{0,1}
+匹配1-n次,優(yōu)先匹配n次,相當(dāng)于{1,}
*匹配0-n次,優(yōu)先匹配n次,相當(dāng)于{0,}
正則默認(rèn)和人心一樣是貪婪的,也就是常說的貪婪模式,凡是表示范圍的量詞,都優(yōu)先匹配上限而不是下限
a{1, 3} // 匹配字符串'aaa'的話,會(huì)匹配aaa而不是a有時(shí)候這不是我們想要的結(jié)果,可以在量詞后面加上?,就可以開啟非貪婪模式
a{1, 3}? // 匹配字符串'aaa'的話,會(huì)匹配a而不是aaa字符邊界
有時(shí)我們會(huì)有邊界的匹配要求,比如以xxx開頭,以xxx結(jié)尾
^在[]外表示匹配開頭的意思
^abc // 可以匹配abc,但是不能匹配aabc
$表示匹配結(jié)尾的意思
abc$ // 可以匹配abc,但是不能匹配abcc
上面提到的\b表示單詞的邊界
abc\b // 可以匹配 abc ,但是不能匹配 abcc
選擇表達(dá)式
有時(shí)我們想匹配x或者y,如果x和y是單個(gè)字符,可以使用字符集,[abc]可以匹配a或b或c,如果x和y是多個(gè)字符,字符集就無能為力了,此時(shí)就要用到分組
正則中用|來表示分組,a|b表示匹配a或者b的意思
123|456|789 // 匹配 123 或 456 或 789
分組與引用
分組是正則中非常強(qiáng)大的一個(gè)功能,可以讓上面提到的量詞作用于一組字符,而非單個(gè)字符,分組的語(yǔ)法是圓括號(hào)包裹(xxx)
(abc){2} // 匹配abcabc分組不能放在[]中,分組中還可以使用選擇表達(dá)式
(123|456){2} // 匹配 123123、456456、123456、456123和分組相關(guān)的概念還有一個(gè)捕獲分組和非捕獲分組,分組默認(rèn)都是捕獲的,在分組的(后面添加?:可以讓分組變?yōu)榉遣东@分組,非捕獲分組可以提高性能和簡(jiǎn)化邏輯
'123'.match(/(?:123)/) // 返回 ['123'] '123'.match(/(123)/) // 返回 ['123', '123']
和分組相關(guān)的另一個(gè)概念是引用,比如在匹配html標(biāo)簽時(shí),通常希望<xxx></xxx>后面的xxx能夠和前面保持一致
引用的語(yǔ)法是\數(shù)字,數(shù)字代表引用前面第幾個(gè)捕獲分組,注意非捕獲分組不能被引用
<([a-z]+)><\/\1> // 可以匹配 `<span></span>` 或 `<div></div>`等
預(yù)搜索
如果你想匹配xxx前不能是yyy,或者xxx后不能是yyy,那就要用到預(yù)搜索
js只支持正向預(yù)搜索,也就是xxx后面必須是yyy,或者xxx后面不能是yyy
1(?=2) // 可以匹配12,不能匹配22 1(?!2) // 可有匹配22,不能匹配12
修飾符
默認(rèn)正則是區(qū)分大小寫,這可能并不是我們想要的,正則提供了修飾符的功能,修復(fù)的語(yǔ)法如下
/xxx/gi // 最后面的g和i就是兩個(gè)修飾符
g正則遇到第一個(gè)匹配的字符就會(huì)結(jié)束,加上全局修復(fù)符,可以讓其匹配到結(jié)束
i正則默認(rèn)是區(qū)分大小寫的,i可以忽略大小寫
m正則默認(rèn)情況下,^和只能匹配字符串的開始和結(jié)尾,m修飾符可以讓和只能匹配字符串的開始和結(jié)尾,m修飾符可以讓^和只能匹配字符串的開始和結(jié)尾,m修飾符可以讓和匹配行首和行尾,不理解就看例子
/jing$/ // 能夠匹配 'yanhaijing,不能匹配 'yanhaijing\n' /jing$/m // 能夠匹配 'yanhaijing, 能夠匹配 'yanhaijing\n' /^jing/ // 能夠匹配 'jing',不能匹配 '\njing' /^jing/m // 能夠匹配 'jing',能夠匹配 '\njing'
圖形化工具
有時(shí)我們會(huì)遇到特別復(fù)雜的正則,有時(shí)候可能不太直觀,下面推薦一個(gè)圖形化展示的工具,我們把涉及到的語(yǔ)法羅列一下
/^[a-z]*[^\d]{1,10}?(aaa|bbb)(?:ccc)$/可以看到工具能夠更快的幫我們理清頭緒

JavaScript中的正則
在js中創(chuàng)建正則有兩種辦法,字面量和new,和創(chuàng)建其他類型變量一樣
var reg = /abc/g // 字面量
var reg = new RegExp('abc', 'g') // new方式,意思和上面一樣js中用到正則的地方有兩個(gè)入口,正則的api和字符串的api,RegExp#test等于RegExp.prototype.test
- RegExp#test
- RegExp#exec
- String#search
- String#match
- String#split
- String#replace
RegExp#test
每個(gè)正則實(shí)例都有test方法,test的參數(shù)是字符串,返回值是布爾值,表示當(dāng)前正則是否能匹配指定的字符串
/abc/.test('abc') // true
/abc/.test('abd') // falseRegExp#exec
exec使用方法和test一樣,只是返回值并不是布爾值,而是返回匹配的結(jié)果
匹配成功返回一個(gè)數(shù)組,數(shù)組第一項(xiàng)是匹配結(jié)果,后面一次是捕獲的分組
/abc(d)/.exec('abcd') // ["abcd", "d", index: 0, input: "abcd"]此數(shù)組還有另外兩個(gè)參數(shù),input是輸入的字符串,index表示匹配成功的序列在輸入字符串中的索引位置
如果有全局參數(shù)(g),第二次匹配時(shí)將從上次匹配結(jié)束時(shí)繼續(xù)
var r1 = /ab/
r1.exec('ababab') // ['ab', index: 0]
r1.exec('ababab') // ['ab', index: 0]
var r2 = /ab/g
r2.exec('ababab') // ['ab', index: 0]
r2.exec('ababab') // ['ab', index: 2]
r2.exec('ababab') // ['ab', index: 4]這一特性可以被用于循環(huán)匹配,比如統(tǒng)計(jì)字符串中abc的次數(shù)
var reg = /abc/g
var str = 'abcabcabcabcabc'
var num = 0;
var match = null;
while((match = reg.exec(str)) !== null) {
num++
}
console.log(num) // 5如果匹配失敗則返回null
/abc(d)/.exec('abc') // nullString#search
search方法返回匹配成功位置的索引,參數(shù)是字符串或正則,結(jié)果是索引
'abc'.search(/abc/) // 0 'abc'.search(/c/) // 2
如果匹配失敗則返回-1
'abc'.search(/d/) // -1 'abc'.search(/d/) !== -1 // false 轉(zhuǎn)換為布爾值
String#match
match方法也會(huì)返回匹配的結(jié)果,匹配結(jié)果和exec類似
'abc'.match(/abc/) // ['abc', index: 0, input: abc] 'abc'.match(/abd/) // null
如果有全局參數(shù)(g),match會(huì)返回所有的結(jié)果,并且沒有index和input屬性
'abcabcabc'.match(/abc/g) // ['abc', 'abc', 'abc']
String#split
字符串的split方法,可以用指定符號(hào)分隔字符串,并返回?cái)?shù)據(jù)
'a,b,c'.split(',') // [a, b, c]其參數(shù)也可以使一個(gè)正則,如果分隔符有多個(gè)時(shí),就必須使用正則
'a,b.c'.split(/,|\./) // [a, b, c]
String#replace
字符串的replace方法,可以將字符串的匹配字符,替換成另外的指定字符
'abc'.replace('a', 'b') // 'bbc'其第一個(gè)參數(shù)可以是正則表達(dá)式,如果想全局替換需添加全局參數(shù)
'abc'.replace(/[abc]/, 'y') // ybc 'abc'.replace(/[abc]/g, 'y') // yyy 全局替換
在第二個(gè)參數(shù)中,也可以引用前面匹配的結(jié)果
'abc'.replace(/a/, '$&b') // abbc $& 引用前面的匹配字符 'abc'.replace(/(a)b/, '$1a') // aac &n 引用前面匹配字符的分組 'abc'.replace(/b/, '$\'') // aac $` 引用匹配字符前面的字符 'abc'.replace(/b/, "$'") // acc $' 引用匹配字符后面的字符
replace的第二個(gè)參數(shù)也可以是函數(shù),其第一個(gè)參數(shù)是匹配內(nèi)容,后面的參數(shù)是匹配的分組
'abc'.replace(/\w/g, function (match, $1, $2) {
return match + '-'
})
// a-b-c-RegExp
RegExp是一個(gè)全局函數(shù),可以用來創(chuàng)建動(dòng)態(tài)正則,其自身也有一些屬性
- $_
- $n
- input
- length
- lastMatch
來個(gè)例子
/a(b)/.exec('abc') // ["ab", "b", index: 0, input: "abc"]
RegExp.$_ // abc 上一次匹配的字符串
RegExp.$1 // b 上一次匹配的捕獲分組
RegExp.input // abc 上一次匹配的字符串
RegExp.lastMatch // ab 上一次匹配成功的字符
RegExp.length // 2 上一次匹配的數(shù)組長(zhǎng)度實(shí)例屬性
正則表達(dá)式的實(shí)例上也有一些屬性
- flags
- ignoreCase
- global
- multiline
- source
- lastIndex
還是看例子
var r = /abc/igm; r.flags // igm r.ignoreCase // true r.global // true r.multiline // true r.source // abc
lastIndex比較有意思,表示上次匹配成功的是的索引
var r = /abc/igm;
r.exec('abcabcabc')
r.lastIndex // 3
r.exec('abcabcabc')
r.lastIndex // 6可以更改lastIndex讓其重新開始
var r = /abc/igm;
r.exec('abcabcabc') // ["abc", index: 0]
r.exec('abcabcabc') // ["abc", index: 3]
r.lastIndex = 0
r.exec('abcabcabc') // ["abc", index: 0]實(shí)戰(zhàn)實(shí)例
來幾個(gè)常用的例子
/(?:0\d{2,3}-)?\d{7}/ // 電話號(hào) 010-xxx xxx
/^1[378]\d{9}$/ // 手機(jī)號(hào) 13xxx 17xxx 18xxx
/^[0-9a-zA-Z_]+@[0-9a-zA-Z]+\.[z-z]+$/ // 郵箱去除字符串前后空白
str = str.replace(/^\s*|\s*$/g, '')
總結(jié)
刻意練習(xí),方能游刃有余,知己知彼,方能百戰(zhàn)百勝,正則是前端的一個(gè)武器,技多不壓身。
到這里你已經(jīng)學(xué)會(huì)了正則的語(yǔ)法,并且學(xué)會(huì)了在js中使用正則的方法,接下來快去實(shí)戰(zhàn)吧,要想學(xué)會(huì)正則必須多加練習(xí),正所謂拳不離手曲不離口嗎。
到此這篇關(guān)于全面學(xué)習(xí)正則表達(dá)式 - 從原理到實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)正則表達(dá)式原理到實(shí)戰(zhàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
正則表達(dá)式:過濾<font>和</font>
正則表達(dá)式:過濾<font>和</font>...2007-04-04
JavaScript常用的正則表達(dá)式表單驗(yàn)證代碼
驗(yàn)證表單的不同內(nèi)容用的是不同的正則表達(dá)式??蛻舳蓑?yàn)證常用的幾個(gè)。2010-12-12

