新聞中心
前言
正則,熟悉的陌生人,我們?cè)诒韱涡r?yàn)中見(jiàn)到它,也在框架源碼 html 轉(zhuǎn) ast 樹(shù)的 parser 原理中見(jiàn)到它;常常見(jiàn)到,需要時(shí)百度一搜,確實(shí)能用,卻又一碰到就發(fā)憷,原因很簡(jiǎn)單,這火星文,誰(shuí)看得懂呀!

本文目標(biāo),帶你走進(jìn)正則世界,作為一篇認(rèn)真負(fù)責(zé)的科普文,一定要做到讓你們一遍學(xué)懂卻不會(huì),于是反復(fù)來(lái)查看。
正則歷史
正則其實(shí)就是規(guī)則的設(shè)定,用于驗(yàn)證或者獲取信息。
真正起源于神經(jīng)網(wǎng)絡(luò)
20 世紀(jì) 40 年代,兩位神經(jīng)生理學(xué)家研究出了一種用數(shù)學(xué)方式描述神經(jīng)網(wǎng)絡(luò)的方法,并以此在 1956 年發(fā)表了一篇論文《正則表達(dá)式搜索算法》,主要描述了一種叫做正則集合(Regular Sets)的符合。
在計(jì)算機(jī)世界大放異彩
UNIX 之父在十年后的 1968 年,發(fā)表文章《正則表達(dá)式搜索算法》,并將正則移植到了大名鼎鼎的文本搜索工具grep中。
正則為什么存在
理解一個(gè)東西,不要一上來(lái)就背應(yīng)用層的 API,要去理解,人的大腦本來(lái)就是被設(shè)計(jì)成對(duì)理解的東西很容易記憶,不要浪費(fèi)自己的天賦。
我們說(shuō)過(guò),正則其實(shí)就是規(guī)則的設(shè)定,用于驗(yàn)證或者獲取信息。匹配動(dòng)作最粗暴的無(wú)疑是一一對(duì)應(yīng),a 對(duì) a,b 對(duì) b,這個(gè)規(guī)則就是完全一樣才匹配,但這無(wú)疑太低效;一個(gè)事物很容易有共性,共性構(gòu)成集合,比如手機(jī)號(hào) 13 位,郵箱帶@等等,正則就是讓我們更高效的匹配或獲取這些特定規(guī)則集合的存在。
正則如何做到
正則中的處理方式就是設(shè)定子規(guī)則,讓某些符號(hào)不再代表本身,而是代表一些子規(guī)則,就像搭建大樓,我們希望找到自己想要的規(guī)則,就得用合適的最小磚塊,再設(shè)定使用量,就搭建完成了。
這個(gè)子規(guī)則,就是元字符,如我們常見(jiàn)的\d,代表單個(gè) 0-1 數(shù)字,\s就是換行指標(biāo)等空白字符;需要注意的是,我們剛剛一直在強(qiáng)調(diào)單個(gè),這其實(shí)也很好理解,對(duì)于文本而言,最小單元自然是單個(gè)字符,有了最小單元,我們?cè)偌由现貜?fù)規(guī)模,就可以搭建我們自己的大樓了。
至此,我們對(duì)正則世界基本的了解算是到位了,開(kāi)始更接地氣的分享叭!
磚塊:元字符
那我們先來(lái)了解元字符,有四個(gè)維度,分別是【字符組】、【取反字符組】、【常用字符組】、【空白字符】,可以記憶為 【3 + 1】,依次理解。
字符組
基礎(chǔ)使用
對(duì)于單字符選擇而言,在正則中的術(shù)語(yǔ)被稱為字符組,接下來(lái)我們都會(huì)用這個(gè)術(shù)語(yǔ),但不要被迷惑,它并不是匹配一組數(shù)據(jù),而只是匹配一組數(shù)據(jù)中的一個(gè)字符,這點(diǎn)很關(guān)鍵。
語(yǔ)法:[xxx]。
匹配規(guī)則:目標(biāo)文本需包含【任意一個(gè)包含在括號(hào)中的元素】。
獲取信息規(guī)則:將獲取第一個(gè)【任意一個(gè)包含在括號(hào)中的元素】。
舉例:/[abc]/這個(gè)正則將匹配 a、b、c 中的任何一位且只有一位,默認(rèn)匹配第一位,使用測(cè)試平臺(tái)會(huì)得到如下結(jié)果。
取反字符組
取反邏輯
正常使用是范圍內(nèi)選取,不過(guò)也會(huì)出現(xiàn)【除了這些之外】的范圍選取,這時(shí)就需要用到取反了。
語(yǔ)法:[^xxx]。
匹配規(guī)則:目標(biāo)文本需包含【任意一個(gè)不包含在括號(hào)中的元素】。
獲取信息規(guī)則:將獲取第一個(gè)【任意一個(gè)不包含在括號(hào)中的元素】。
舉例:/[^abc]/這個(gè)正則將匹配非 a、b、c 中的任何一位且只有一位,默認(rèn)匹配第一位,使用測(cè)試平臺(tái)會(huì)得到如下結(jié)果。
常用字符組
八二原則同樣適用在字符組中,有很多常見(jiàn)的匹配規(guī)則,沒(méi)必要重復(fù)寫(xiě),于是正則就把這些特殊字符組分別取了個(gè)別名。
主要分為如下【3+1】概念,三對(duì)+一個(gè)。
其他常用字符組。
空白字符這類字符比較特殊,單獨(dú)拎出來(lái),方便后期直接使用。
到此,我們也就知道了如何去匹配單個(gè)字符,這就是我們的“最小規(guī)?!保粋€(gè)個(gè)匹配肯定是不行,那正則將冗長(zhǎng)到難以忍受,所以我們還需要重復(fù),這就是量詞的作用。
要多少塊磚:量詞
理解了字符組,我們就要了解規(guī)模了,這在正則中有個(gè)術(shù)語(yǔ) --- 量詞,還是【3+1】,依次理解。
這個(gè)沒(méi)有很復(fù)雜的東西,唯一要注意的是,正則默認(rèn)是只匹配一次的,即一次匹配完后就算后文還有符合的內(nèi)容也不再獲取,這涉及到修飾符g,后面再補(bǔ)充。
看案例就行,我們還是以[abc]作為字符組最小單元來(lái)演示。
*號(hào):0-n 次
正則:/[abc]*/。
匹配規(guī)則:目標(biāo)文本無(wú)需包含【任意一個(gè)包含在括號(hào)中的元素】,此匹配規(guī)則一定成立。
獲取信息規(guī)則:將獲取第一段【包含在括號(hào)中且連續(xù)的元素組】。
+號(hào):1+n 次
正則:/[abc]+/。
獲取信息規(guī)則:將獲取第一段【包含在括號(hào)中且連續(xù)的元素組】。
匹配規(guī)則:目標(biāo)文本需包含【至少一個(gè)包含在括號(hào)中的元素】。
?號(hào):0 次或 1 次
正則:/[abc]?/。
匹配規(guī)則:此匹配規(guī)則一定成立。
獲取信息規(guī)則:將獲取第一個(gè)【任意一個(gè)包含在括號(hào)中的元素】。
{}符號(hào):精確控制次數(shù)
上面其實(shí)都屬于特殊案例,我們可以通過(guò){}精確控制匹配次數(shù),主要有三個(gè)用法:
- {m}:必須出現(xiàn) m 次。
- {m, n}:可以出現(xiàn) m-n 次。
- {m,}:至少出現(xiàn) m 次。
量詞模式
量詞還涉及到模式問(wèn)題,因?yàn)榱吭~有范圍,這就意味著可取多可取少,但計(jì)算機(jī)是不允許有歧義的,所以量詞存在三種模式:
- 貪婪模式:默認(rèn),會(huì)盡可能匹配多的內(nèi)容。
- 懶惰模式:量詞后面加個(gè)?,會(huì)盡可能少匹配內(nèi)容。
- 獨(dú)占模式:量詞后面加個(gè)+,不觸發(fā)回溯動(dòng)作。
舉例見(jiàn)模式區(qū)別
測(cè)試用例:aaabb。
測(cè)試正則:
- 貪婪模式:/a*/。
- 懶惰模式:/a*?/。
貪婪模式:/a*/。
匹配過(guò)程:
匹配結(jié)果:
對(duì)應(yīng)輸出結(jié)果:['aaa','','','']。
懶惰模式:/a*?/。
匹配過(guò)程:
匹配結(jié)果:
對(duì)應(yīng)輸出結(jié)果:['','a','','a','','a','','','']。
補(bǔ)充案例:
至此,我們就完成了對(duì)量詞規(guī)則的學(xué)習(xí)。
正則模式
既然量詞有模式,正則本身自然也有模式,針對(duì)【大小寫(xiě)、多行、點(diǎn)通配、備注】情況,存在【3+1】種模式。
- 不區(qū)分大小寫(xiě)模式。
- 點(diǎn)通配模式。
- 多行匹配模式。
- 注釋模式。
我們來(lái)逐一了解:
不區(qū)分大小寫(xiě)模式(Case-Insensitive)
語(yǔ)法:/(?i)reg/ 對(duì)應(yīng) js 為 /reg/i。
注意點(diǎn):
- 不區(qū)分大小寫(xiě)模式的指定方式,使用模式修飾符 (?i)。
- 修飾符如果在括號(hào)內(nèi),作用范圍是這個(gè)括號(hào)內(nèi)的正則,而不是整個(gè)正則。
作用:忽略大小寫(xiě)進(jìn)行匹配。
正則:/(?i)(cat) \1/ 對(duì)應(yīng) js 為 /(cat) \1/i。
如果這時(shí)候我們希望重復(fù)單詞間保持大小寫(xiě)完全一致,可以使用如下正則。
正則:/((?i)cat) \1/ 對(duì)應(yīng) js 為 暫無(wú)。
點(diǎn)通配模式(單行匹配模式 -- Single Line)
語(yǔ)法:/(?s)reg/ 對(duì)應(yīng) js 為暫無(wú)。
注意點(diǎn):
作用:使得.元字符可以匹配包括換行在內(nèi)的所有字符。
多行匹配模式
語(yǔ)法:/(?m)reg/ 對(duì)應(yīng) js 為/reg/m。
注意點(diǎn):
作用:使得^和$可以匹配上每行的開(kāi)頭或結(jié)尾。
使用前正則:/^the|cat$/。
使用后正則:/(?m)^the|cat$/ 對(duì)應(yīng) js 為/^the|cat$/m。
注釋模式
語(yǔ)法:/(?#)reg/ 對(duì)應(yīng) js 為 暫無(wú)。
注意點(diǎn):
作用:使得正則支持添加備注信息。
使用正則案例:/(\w+)(?#word) \1(?#word repeat again)/。
正則位置信息
對(duì)于匹配而言,就像我們看一個(gè)人是不是自己要找的人,不只有對(duì)著畫(huà)像、照片一直看這一個(gè)方法,也可以描述 TA 在什么東西的旁邊、TA 面前是什么、背后是什么等等,這些位置信息在正則中同樣有需求,并且有個(gè)專門的術(shù)語(yǔ) -- 斷言。
斷言,即斷定匹配文本的位置關(guān)系;前后的內(nèi)容是什么、中止的位置在哪之類,落實(shí)下來(lái)分為三類:?jiǎn)卧~邊界、行的開(kāi)始/結(jié)束、環(huán)視。
行的開(kāi)始/結(jié)束
這個(gè)我們或多或少都接觸過(guò),如果我們要求匹配的內(nèi)容出現(xiàn)在一行文本的開(kāi)頭或結(jié)尾,就可以使用^和$進(jìn)行位置界定。
結(jié)合之前說(shuō)的【模式】中多行模式的概念,默認(rèn)處理文本會(huì)被正則當(dāng)成一行進(jìn)行處理,無(wú)論其是否換行,這是的開(kāi)始結(jié)束就等同于文首和文末;而如果想處理多行情況,只需要改變模式為多行匹配即可,js 中語(yǔ)法為/reg/m。
單詞邊界(Word Boundary)
多行模式+^$可以在行的維度處理邊界問(wèn)題,但如果是單詞,就無(wú)能為力了,如我們希望在下面文本中替換tom這個(gè)人名為jerry。
tom asked me if I would go fishing with him tomorrow.
這時(shí)如果替換的正則是/tom/ ,就會(huì)出現(xiàn)這種錯(cuò)誤的替換現(xiàn)象。
很明顯,我們要的就是tom,而并不是只要包含 tom 就可以的部分,這時(shí)我們就可以使用到單詞邊界的概念,設(shè)定開(kāi)始截止,避免出現(xiàn)匹配歧義。
基礎(chǔ)概念
語(yǔ)法:\b。
作用:匹配到\w即【[A-Za-z0-9_]】表示范圍之外的字符就中止匹配,可以理解為邊界(Boundary)。
實(shí)例
環(huán)視
我們剛剛說(shuō)了邊界,包括單詞和行的邊界,其實(shí)邊界也就是要求匹配文本的前后一定是特定的內(nèi)容,只是這個(gè)特定內(nèi)容對(duì)行來(lái)說(shuō)是^$,對(duì)單詞邊界來(lái)說(shuō)是$。
那我們把這個(gè)特定范圍再靈活點(diǎn),對(duì)于一段內(nèi)容而言,有前后兩個(gè)方向、滿足或者不滿足兩個(gè)情況,意味著有四種情況,如下表。
總結(jié)下來(lái)其實(shí)就是:有尖括號(hào)則為左,等號(hào)肯定感嘆否。
正則邏輯信息
根據(jù)前文,我們已經(jīng)學(xué)習(xí)了【字符組】和【量詞】的概念,就像一門編程語(yǔ)言,有組成物料還不夠,自然還需要一些邏輯判斷,在正則中也存在【邏輯元字符】這一概念。
邏輯元字符
|號(hào):或邏輯
某個(gè)資源可能以 http:// 開(kāi)頭,或者 https:// 開(kāi)頭,也可能以 ftp:// 開(kāi)頭,那么資源的 協(xié)議部分,我們可以使用 (https?|ftp):// 來(lái)表示。
正則優(yōu)先級(jí)提升之分組
在正則中存在分組的概念,主要有兩點(diǎn)作用:整體和復(fù)用。
整體
代表避免語(yǔ)義分析有歧義,如【匹配 15 位數(shù)字或 18 位數(shù)字】,這時(shí)如果寫(xiě)出這樣的正則/\d{15}\d{3}?/;后面的\d{3}?將代表懶惰模式匹配,這個(gè)正則會(huì)只匹配 18 位數(shù)字而非 15 位。
測(cè)試正則:/\d{15}\d{3}?/。
這里就存在確定\d{3}是一個(gè)整體的需求,這可以使用分組實(shí)現(xiàn)。
測(cè)試正則:/\d{15}(\d{3})?/。
復(fù)用有些時(shí)候,我們也會(huì)需要用到之前匹配到的結(jié)果,如【查看文本中的連續(xù)重復(fù)單詞】,解決思路就變成了。
- 寫(xiě)出匹配單個(gè)單詞的正則。
- 使用之前的結(jié)果進(jìn)行再次匹配。
第二點(diǎn),就是通過(guò)分組實(shí)現(xiàn)的;先了解下基礎(chǔ)概念。
基礎(chǔ)概念
語(yǔ)法:定義使用() ,正則中訪問(wèn)使用\編號(hào),方法中訪問(wèn)使用$編號(hào)。
作用:用于分組,被括號(hào)括起來(lái)的部分默認(rèn)將被保存為子組,正則中可以通過(guò)子組編號(hào)訪問(wèn),子組編號(hào)從一遞增,也可以用語(yǔ)法(?:)從而不保存子組,避免占用編號(hào)。
分組引用語(yǔ)法詳解
分組引用
假定分組編號(hào)為number,則可以使用\number進(jìn)行引用。
多編號(hào)情況
左括號(hào)是第幾個(gè),那就是第幾個(gè)分組。
不保存子組
使用此語(yǔ)法后不會(huì)為這個(gè)子組分配編號(hào)。
替換功能
命名分組
V8 目前已經(jīng)完全實(shí)現(xiàn)了命名捕獲分組的提案 https://tc39.github.io/proposal-regexp-named-groups/,一起來(lái)了解下吧!
基礎(chǔ)概念
語(yǔ)法:定義使用(?) ,正則中訪問(wèn)使用\k,方法中訪問(wèn)使用$。
作用:用于命名分組,不再使用編號(hào)訪問(wèn)而是直接通過(guò)分組變量名訪問(wèn),更加準(zhǔn)確。
API 結(jié)合解構(gòu)賦值
在 js 關(guān)于正則的方法中,如果存在命名分組,會(huì)存在groups屬性,里面存放著每個(gè)命名分組的名稱以及它們匹配到的值;結(jié)合解構(gòu)賦值,會(huì)有很神奇的功效。
在 exec() 和 match() 中的使用:
exec() 和 match() 方法返回的匹配結(jié)果數(shù)組上多了一個(gè) groups 屬性,里面存放著每個(gè)命名分組的名稱以及它們匹配到的值。
const {day, month, year} = "04-25-2017".match(/(?\d{2})-(?\d{2})-(?\d{4})/).groups 在 replace(/.../, replacement) 中的使用:
當(dāng)replacement為函數(shù)時(shí),在實(shí)參列表的最末尾,多傳了一個(gè) groups 對(duì)象。
"04-25-2017".replace(/(?\d{2})-(? \d{2})-(? \d{4})/, (...args) => {
const groups = args.slice(-1)[0]
const {day, month, year} = groups
return `${day}-${month}-${year}`
})
正則編程
這是最最關(guān)鍵的部分,學(xué)來(lái)就得用上呀,我們來(lái)分享在正則在前端編程中的應(yīng)用。
正則最終還是要落實(shí)到編程語(yǔ)言中來(lái),讓我們來(lái)看下正則編程吧!
正則的處理可以區(qū)分為如下四類:
- 校驗(yàn)文本內(nèi)容。
- 提取文本內(nèi)容。
- 替換文本內(nèi)容。
- 切割文本內(nèi)容。
讓我們逐一了解。
校驗(yàn)文本內(nèi)容
需注意:關(guān)于 lastIndex,即正則會(huì)將下一次匹配開(kāi)始的位置 ;字符串的四個(gè)方法,每次匹配都是從 0 開(kāi)始的,即 lastIndex 不變;而正則的兩個(gè)方法 exec 和 test ,如果是全局匹配,則每次匹配完都會(huì)改變 lastIndex 的值,這就會(huì)導(dǎo)致可能出現(xiàn)【處理兩次,第一次成功,第二次失敗】的情況。
var regex = new RegExp(/^\d{4}-\d{2}-\d{2}/, 'g')
regex.test('2021-12-21') // true
console.log(regex.lastIndex ) // 10
regex.test('2021-12-21') // false
console.log(regex.lastIndex ) // 0由于我們這里是文本校驗(yàn),并不需要找出所有的。所以建議 JavaScript 中文本校驗(yàn)在使用 RegExp 時(shí)不要設(shè)置 g 模式。
字符串方法:search
search 會(huì)將字符串轉(zhuǎn)為正則。
正則方法:test
提取文本內(nèi)容
字符串方法:match
match 會(huì)將字符串轉(zhuǎn)為正則。
注意:match 方法的返回值與修飾符 g 有關(guān)(沒(méi)有匹配上時(shí)返回 null)。
- 沒(méi)有 g :返回標(biāo)準(zhǔn)匹配格式,即:數(shù)組的第一個(gè)元素是整體匹配的內(nèi)容,接下來(lái)是分組捕獲的內(nèi)容,然后是整體匹配的第一個(gè)下標(biāo),最后是目標(biāo)字符串。
- 有 g :返回的是一個(gè)包含所有匹配內(nèi)容的數(shù)組。
正則方法:exec
exec 比 match 更強(qiáng)大,可以解決 有修飾符 g 時(shí) match 沒(méi)有索引信息的問(wèn)題,在使用 exec 時(shí),正則會(huì)將下一次匹配開(kāi)始的位置存放在正則的屬性 lastIndex 上。
替換文本內(nèi)容
字符串方法:replace
切割文本內(nèi)容
字符串方法:split
- 可以有第二個(gè)參數(shù),表示結(jié)果數(shù)組的最大長(zhǎng)度。
- 如果正則使用分組時(shí),結(jié)果數(shù)組中是包含分隔符的。
前端相關(guān) API 總結(jié)
string
- match。
- split。
- search。
- replace。
RegExp
- test。
- exec。
總結(jié)
做下總結(jié)吧,繪制知識(shí)圖譜,方便自己記憶,也方便和人分享。
3 + 1 元字符;3 + 1 常用元字符;3 + 1 正則量詞;3 量詞匹配模式;3 + 1 正則匹配模式;3 + 1 正則邏輯
首先物料元字符,有四個(gè)維度,分別是【字符組】、【取反字符組】、【常用字符組】、【空白字符】,可以記憶為 【3 + 1】。
理解了字符組,我們就要了解規(guī)模了,這在正則中有個(gè)術(shù)語(yǔ) --- 量詞還是【3+1】。
量詞還涉及到模式問(wèn)題,因?yàn)榱吭~有范圍,這就意味著可取多可取少,但計(jì)算機(jī)是不允許有歧義的,所以量詞存在三種模式。
既然量詞有模式,正則本身自然也有模式,針對(duì)【大小寫(xiě)、多行、點(diǎn)通配、備注】情況,存在【3+1】種模式。
就像定位,不止需要本身的絕對(duì)信息,還需要看他的相對(duì)位置信息,這個(gè)信息在正則中叫斷言,存在三種情況,【行首尾、單詞邊界和環(huán)視】,其中環(huán)視又存在前后是不是四種情況。
就像編程語(yǔ)言,我們有了零碎的物料是不夠的,還需要邏輯,在正則中存在分支語(yǔ)句|和優(yōu)先級(jí)分組,分組又有三類,默認(rèn)分組、非捕獲分組和命名分組。
至此,我們也就用非常精煉的總結(jié)性語(yǔ)句概括了正則的整體脈絡(luò)啦!
尾聲少年們,心法已定,拿走不謝,希望我能做到讓你們一遍看懂而記不住,要首尾呼應(yīng),嘗試動(dòng)手自己實(shí)現(xiàn)下吧,有些需求會(huì)發(fā)現(xiàn)如果用正則的角度,會(huì)有很多很神奇的實(shí)現(xiàn)方式呀,而且如果能幫助到別人,也超有成就感的。
分享名稱:一文破解正則密碼
文章路徑:http://m.fisionsoft.com.cn/article/dpjodsp.html


咨詢
建站咨詢
