电竞比分网-中国电竞赛事及体育赛事平台

分享

如何教你看懂復(fù)雜的正則表達(dá)式

 昵稱14945998 2019-02-28

【前言】

1.此文針對,正則表達(dá)式的初學(xué)者,老鳥請飄過。

正則表達(dá)式的初學(xué)者,常遇到的情況是,對于相對復(fù)雜一點的正則表達(dá)式,覺得很難理解,很難看懂。

2.此文目的,之前你看不懂,看了此教程后,就基本掌握了,看懂復(fù)雜正則表達(dá)式的思路。

這樣就可以通過自己的能力,一點點把復(fù)雜的正則表達(dá)式,一點點拆分,一點點分析,知道完全理解。

3.在看此文之前,肯定需要你本身對于正則表達(dá)式,已經(jīng)有了一些基本的基礎(chǔ),

比如知道點’.’表示任意字符,星號’*’表示0或多個之類的含義,這樣才有看此文的基礎(chǔ)。

關(guān)于正則表達(dá)式方面的教程和資料,需要的可以去看我整理的一些資料:

正則表達(dá)式學(xué)習(xí)心得

【教程】詳解Python正則表達(dá)式

【總結(jié)】關(guān)于(C#和Python中的)正則表達(dá)式

java中的正則表達(dá)式:java.util.regex

【如何看懂復(fù)雜的正則表達(dá)式】

基本思路:拆分->各個擊破

解釋:

先將一個,很長的,很復(fù)雜的正則表達(dá)式,從左向右,一點點讀取,分析,一點找到某部分的內(nèi)容,是一個邏輯概念上的獨立的一塊,就暫時拆分出來,如此,一點點把復(fù)雜的正則表達(dá)式,拆分成很多個邏輯上獨立的小塊,

然后針對每個小塊的表達(dá)式,再去分析其含義

每個小塊的正則表達(dá)式都搞懂后

把和所有的含義,合并出一個整體的含義

最后就可以實現(xiàn),用人類的語言,把對應(yīng)的復(fù)雜的正則表達(dá)式,一點點解釋出來了,即:

把,之前看不懂的,復(fù)雜的正則表達(dá)式,翻譯成,人類可以看懂讀懂的語言(至少先讓你自己讀懂看懂)

在舉例分析之前,需要知道一些前提:

1.任何復(fù)雜的正則表達(dá)式,都是由寫正則表達(dá)式的人,從簡單到復(fù)雜一點點寫出來的。

所以,理論上,如何讀懂復(fù)雜的正則表達(dá)式,也就是一個反向解析的過程,即將復(fù)雜的拆分成多個簡單的,功能上,邏輯是獨立的子表達(dá)式,然后再去分析其含義,最終再合并出來整體的,復(fù)雜的含義。

2.正則表達(dá)式,即使各種語言的正則表達(dá)式的庫函數(shù),去解析的時候,也是從左到右,一點點分析,一點點拆分,將復(fù)雜的差分成多個子表達(dá)式,以實現(xiàn),計算機語言內(nèi)部,去理解此表達(dá)式的。

此處,只是通過人類的方式,手動從左到右,一點點分析而已,也算是和計算機語言識別正則的類似的過程。

3.雖然正則表達(dá)式,不同的語言,具體的寫法,有些略微的差別,但是本質(zhì)上的,絕大部分的正則表達(dá)式的寫法,都是基本類似的。

【舉例說明,如何實現(xiàn)拆分復(fù)雜的正則表達(dá)式】

舉例:

/^[A-Z]:\\{1,2}[^/:\*\?<>\|]+\.(jpg|gif|png|bmp)$/i正則表達(dá)式表示什么意思?

首先,對于拿到這個,看似很繁瑣的字符串:

/^[A-Z]:\\{1,2}[^/:\*\?<>\|]+\.(jpg|gif|png|bmp)$/i

作為,相對比你熟悉正則的我,一看就知道,是PHP或Perl一類的語言中的正則表達(dá)式,因為這里是:

/xxx/i

的格式,其中xxx表示真正的正則表達(dá)式本身,而后面的i表示ignoreCase,即忽略大小寫的意思。

而如果你只是熟悉其他如Python等語言的正則表達(dá)式,則此處無需太關(guān)心那兩個斜杠,可以將其理解為,類似于Python中的這樣的寫法:

re.match("xxx", re.I)

其中的xxx,是此處真正的正則表達(dá)式:

^[A-Z]:\\{1,2}[^/:\*\?<>\|]+\.(jpg|gif|png|bmp)$

而re.I即re.IGNORECASE,表示忽略大小寫的意思。

接下來,就來分析此處的xxx,即:

^[A-Z]:\\{1,2}[^/:\*\?<>\|]+\.(jpg|gif|png|bmp)$

的完整的含義:

對于我來說,看到此正則表達(dá)式:

^[A-Z]:\\{1,2}[^/:\*\?<>\|]+\.(jpg|gif|png|bmp)$

后,我可以直接將其,按照之前所介紹的方法,直接拆分出對應(yīng),幾個子表達(dá)式,其中每個子表達(dá)式,相對來說,是邏輯上獨立的,或者是沒關(guān)系,關(guān)系不大的各個小的正則表達(dá)式。

先說拆分的結(jié)果如下:

1^
2[A-Z]
3:
4\\{1,2}
5[^/:\*\?<>\|]+
6\.
7(jpg|gif|png|bmp)
8$

但是,作為讀者的你,肯定看了會說,我怎么才能,像我這里一樣,一次性就看出,如何將上述復(fù)雜的正則表達(dá)式,一下次分出這8部分,即(將上面那個復(fù)雜的正則表達(dá)式)大卸八塊呢?^_^

那么此處,就來介紹一下,基本的思路,或者說,我是怎么實現(xiàn)此過程的:

【如何拆分正則表達(dá)式: ^[A-Z]:\\{1,2}[^/:\*\?<>\|]+\.(jpg|gif|png|bmp)$】

首先,看到這么一堆的復(fù)雜的字符,其實我也不可能立刻實現(xiàn),全部拆分出來。

我也是一點點,像之前介紹的方法和思路一樣,是從左到右,一點點去,識別,區(qū)分,然后一點點分出來這么多個子表達(dá)式,子部分的:

1.比如,首先,我從左往右看的話,第一個看到的是’^’,對此,對于有了正則表達(dá)式最最基礎(chǔ)的你,應(yīng)該知道,這個是匹配字符串的開始的;

而很明顯,對于’^’,此處,一般不會,此處也沒有后面有啥限定符,即沒有和其他字符,去搭配使用。

所以,此’^’,就是我們所拆分出來的,第一個,相對邏輯上獨立的,子正則表達(dá)式,所以就可以寫出第一個小子表達(dá)式了:

1^

2.然后接著來分析,接下來是左中括號'[',而對于左中括號,還是那句話,作為已有正則表達(dá)式的基礎(chǔ)的你,知道其,一般來說都是和另外一個右中括號’]’去搭配使用,并且左右中括號里面,也會有一些字符,以表示中括號內(nèi)的字符,所組成的集合,即類似于[xxx]的形式,對此,接著往后看,可以說,此處還是很簡單的,就看到了后面還有’A-Z]’,正好和'['組成了'[A-Z]’,正好符合我們所理解和期望的[xxx]的形式。

而此處,很明顯,就是A-Z,對應(yīng)著正則表達(dá)式的語法,在中括號內(nèi),可以通過短橫線鏈接起始字符,表示一段范圍內(nèi)的字符,此處即通過A-Z表示,A,B,C,。。。,X,Y,Z,這26個大寫字母。

所以,此處,看似,也就很清楚了,覺得第二個子正則表達(dá)式,就是[A-Z]了。

而作為比你經(jīng)驗稍多的我,要告訴你,其實你此處這樣的想法,是嚴(yán)謹(jǐn)?shù)模驗?,對于,中括號?nèi)部表示字符集合,[xxx]的寫法,往往后面還會跟著一些限定符,去表示此集合字符的個數(shù)方面的限定,比如加號’+’表示去匹配,往后數(shù),盡可能多個,比如表示最少2個,最多5個的'{2,5}’等等。

而此處呢,算是巧了,后面實際上,是沒有這類限定符的,因為我們看到了,后面只有冒號’:’,而冒號,此處,正如按照正常邏輯所理解的一樣,就是表示匹配冒號字符’:’本身而已。

所以,此處,由于巧了,后面沒有字符個數(shù)方面的限定符,所以,第二個子正則表達(dá)式,正好就是[A-Z]本身而已,所以,接著寫出,我們已經(jīng)拆分出來的,共兩個子正則表達(dá)式了:

1^
2[A-Z]

3.上面已經(jīng)分析了,此處后面跟著的字符,是冒號這個字符’:’,同理,由于后面沒有看到其他的加號’+’之類的限定符,所以此處,冒號本身,就是表示一個完整的子正則表達(dá)式,去匹配單個的冒號了。

所以,此處第三個,子正則表達(dá)式也就是此冒號字符本身了。所以,現(xiàn)在共拆分出來三個子正則表達(dá)式了:

1^
2[A-Z]
3:

4.可以看到,冒號后面是個反斜杠’\’,而看到反斜杠,作為已了解正則表達(dá)式的語法的你,應(yīng)該知道,正則表達(dá)式中,會有很多’\x’其中x是某個字母的形式,而不同的字符,組合出來的,表示不同的各種含義,比如常見的\d表示數(shù)字0-9等等。

而此處,看到的是反斜杠后面’\’后面,又跟了個反斜杠’\’,對此,根據(jù)正則表達(dá)式的語法,則是表示反斜杠這個字符本身,就是想要去匹配一段字符串中,是否有反斜杠這個字符本身。

然后接著往后看,是{1,2},很明顯,是之前已提到多次的,限定符,作用是,限制(前面的字符的)個數(shù)是,至少1個,最多2個。所以此處就是去限定前面的,反斜杠字符本身,所以加起來,就是\\{1,2},而對應(yīng)的含義也就是

去匹配,至少一個反斜杠,最多2個反斜杠。

所以,目前已拆分出共4個子表達(dá)式了:

1^
2[A-Z]
3:
4\\{1,2}

5.再往后面分析,是左中括號'[',根據(jù)正則表達(dá)式的語法,和前面已經(jīng)討論過一次中括號的用法,我們可以知道,后面一定還有一個右中括號,所以,把左右中括號,以及中間內(nèi)容,都一起寫出來,就是:

[^/:\*\?<>\|]

但是,對于中括號中間的這么一堆字符:

^/:\*\?<>\|

至少看起來,也還是比較復(fù)雜的。

再但是呢,對于已經(jīng)了解正則表達(dá)式語法的你,應(yīng)該知道,中括號內(nèi),表示取反的寫法是,對應(yīng)的字符或字符集,在其前面,添加上那個特殊字符,向上的箭頭,此處叫做插入字符’^’,表示針對某個,或某些字符,取反的意思,即匹配除了這些字符之外的那些字符。

而此處,就是對應(yīng)的

對于

/:\*\?<>\|

前面加上個插入符號’^’,變成:

^/:\*\?<>\|

表示,匹配,除了 字符組合:

/:\*\?<>\|

之外的字符。

而此處的字符組合:

/:\*\?<>\|

其實就是一堆的字符,一點點寫出來的,其詳細(xì)含義,我們后續(xù)再分析。

此處還沒完,因為此處的[^xxx]的形式之后,還有個加號’+’,對應(yīng)含義也很明確,就是前面那種字符,即除了/:\*\?<>\|之外的字符,的個數(shù),此處通過加號去限定為,至少是1個,可以更多個,即>=1的個數(shù)。

所以,算是[^xxx]+的形式了,其中xxx是/:\*\?<>\|

因此,此處已經(jīng)共分析出5個子表達(dá)式了:

1^
2[A-Z]
3:
4\\{1,2}
5[^/:\*\?<>\|]+

6.再往后看,就是一個反斜杠’\’加上一個點’.’,即’\.’,其表示點字符本身,這點你也應(yīng)該在學(xué)習(xí)正則表達(dá)式基本語法的時候,有所了解。

此處再多解釋一句就是,之所以不直接寫點’.’,是因為字符點’.’本身,在正則表達(dá)式中,是匹配任意一個單個字符的意思,而想要匹配這樣的,在正則表達(dá)式中被用于表示的含義的字符的時候,就需要用到反斜杠,反斜杠用來表示所謂的轉(zhuǎn)義。

在正則表達(dá)式中,常見的就有:

特殊字符正則表達(dá)式中所代表的特殊含義想要匹配對應(yīng)的字符本身的寫法
.任意單個字符\.
?限定符,表示0或1個\?
*限定符,0或多個\*
( , )左右括號聯(lián)合起來,表示一個group組\( , \)
[ , ]左右中括號括起來,表示字符集合\[ ,  \]

因此,此處一共已拆分出6個子正則表達(dá)式了:

1^
2[A-Z]
3:
4\\{1,2}
5[^/:\*\?<>\|]+
6\.

7.再往后看,后面是一個左括號'(',很明顯,此處后面肯定有一個右括號,和此處的左括號聯(lián)合起來,表示一個組group。

此處,很簡單,就可以看出來是

(jpg|gif|png|bmp)

注:更復(fù)雜的正則表達(dá)式,可能會出現(xiàn)多個group嵌套的情況,即括號內(nèi)嵌套括號的情況,此時,此種拆分方法仍然有效,還是找到最開始的左括號,此時對于括號層次來說肯定是最外層,所匹配的那個的最外層的右括號,那這一部分拿出來,繼續(xù)分析即可。如果存在更多曾的括號嵌套括號,仍然是找到對應(yīng)匹配的括號即可。

而對于此處的group組:

(jpg|gif|png|bmp)

的含義,后面再詳細(xì)分析。

此時,也已經(jīng)拆分出來,共7個子表達(dá)式了:

1^
2[A-Z]
3:
4\\{1,2}
5[^/:\*\?<>\|]+
6\.
7(jpg|gif|png|bmp)

8.最后,還剩下一個美元符號’$’,表示匹配字符串末尾,這個很好理解。不多解釋。

此時,就已經(jīng)實現(xiàn)了,把上述的一個復(fù)雜的正則表達(dá)式,拆分成多個邏輯上獨立的,共8個,子正則表達(dá)式了:

1^
2[A-Z]
3:
4\\{1,2}
5[^/:\*\?<>\|]+
6\.
7(jpg|gif|png|bmp)
8$

看到這里,對于如何從左往右看,一點點根據(jù)邏輯組合,去拆分成多個子表達(dá)式,的總體方法和思路,應(yīng)該大概清楚了。

余下的事情,就是自己通過多讀多看多學(xué)習(xí),去了解別人寫的正則表達(dá)式,用此套分析方法,去拆分了。

知道了方法,加上盡量多的練習(xí),自然會對正則表達(dá)式,越來越熟悉,越來越理解的。

此處,對于此正則表達(dá)式的分析,還沒完。因為還有幾個字正則表達(dá)式的含義,沒有完全分析透徹。

下面先來總結(jié)一下,已經(jīng)知道的,各個子表達(dá)式的含義:

子正則表達(dá)式序號子正則表達(dá)式內(nèi)容子正則表達(dá)式的含義仍需后續(xù)分析的部分子表達(dá)式
1^匹配字符串的開始
2[A-Z]匹配單個字符,此單個字符可能是A-Z中的任何一個
3:匹配冒號字符’:’本身
4\\{1,2}匹配反斜杠字符,最少1個,最多2個
5[^/:\*\?<>\|]+匹配除了 /:\*\?<>\| 之外的其他字符,個數(shù)上則是盡可能多個/:\*\?<>\| 的含義
6\.匹配字符點’.’本身
7(jpg|gif|png|bmp)匹配group,group內(nèi)部是jpg|gif|png|bmpjpg|gif|png|bmp 的含義
8$匹配正則表達(dá)式的末尾

很明顯,還剩兩個我們沒有分析,下面就來詳細(xì)分析解釋其含義:

1./:\*\?<>\| 的含義

其實,理論上,對于這樣的字符串:

/:\*\?<>\|

其實也是繼續(xù)將其按照上述方法,去將其拆分為不同的子表達(dá)式。

只是由于此處看似復(fù)雜,其實還是很簡單,所以,直接分析一下,即可看出其含義。就不詳細(xì)拆分了。

此處,根據(jù)字符本身含義,依次是:

/斜杠字符本身
:冒號字符本身
\*星號字符’*’本身
\?問號字符’?’本身
<小于號字符'<'本身
>大于號字符’>’本身
\|豎線字符’|’本身

所以,此部分

的總體含義就是:

字符,斜杠,冒號,星號,問號,小于號,大于號,豎線,這些字符(集合)

而放到[^xxx]里面,變成:

[^/:\*\?<>\|]

的意思就是

除了字符:

斜杠,冒號,星號,問號,小于號,大于號,豎線

這些字符之外的,其他的任意字符

而再加上之前的加號’+’去限定其個數(shù)是最少1個,>=1個,變成:

[^/:\*\?<>\|]+

所表示的意思就很清楚了:

去匹配 盡可能多個字符,這些字符是:

除了字符:

斜杠,冒號,星號,問號,小于號,大于號,豎線

之外的,其他的任意的字符

到此,對此

[^/:\*\?<>\|]+

的含義,才算基本明確。

而如果你本身對于windows等操作系統(tǒng)對于文件名或者路徑字符的限制有了解的話,你會發(fā)現(xiàn),這基本上就是

我們所常見的,對于你在windows中,問文件或文件夾命名時,其所提示的,不允許你名字中包含這類:

斜杠,冒號,星號,問號,小于號,大于號,豎線

即:

/,:,*,?,<,>,|

而此時,如果你稍微會點舉一反三/觸類旁通的思想的話,就會聯(lián)想到,此處去匹配的東西,很可能是文件或文件夾的名字方面的東西。

2.jpg|gif|png|bmp 的含義

此處的正則表達(dá)式,很明顯看出就是:

xxx|xxx|xxx

的格式,其中xxx分別是,具有不同可能的字符串,即多個可能性之一

對應(yīng)的,其所表達(dá)的意思是,去匹配:

要么是jpg,要么是gif,要么是png,要么是bmp

(除了這幾種可能外,其他的都不匹配)

對于這種匹配多種可能性的正則的寫法,想要深入了解的話,可以參考教程:

【教程】詳解Python正則表達(dá)式之: '|’ vertical bar 豎杠

所以,此時,我們就可以把每部分的內(nèi)容的含義,都完整分析出來了:

子正則表達(dá)式序號子正則表達(dá)式內(nèi)容子正則表達(dá)式的含義
1^匹配字符串的開始
2[A-Z]匹配單個字符,此單個字符可能是A-Z中的任何一個
3:匹配冒號字符’:’本身
4\\{1,2}匹配反斜杠字符,最少1個,最多2個
5[^/:\*\?<>\|]+匹配 >=1個,但盡可能多的,除了斜杠,冒號,星號,問號,小于號,大于號,豎線之外的其他的任意字符
6\.匹配字符點’.’本身
7(jpg|gif|png|bmp)匹配要么是jpg,要么是gif,要么是png,要么是bmp
8$匹配正則表達(dá)式的末尾

所以,把這些各個子正則的含義,連接在一起,就可以用語言表示為:

去匹配一個字符串,

該字符串,開頭部分,就一個字母,該字母可能是從A到Z的任何一個字母,

后面跟著一個冒號,

再后面是1個或2個反斜杠,

然后是至少一個,但盡量多的,除了斜杠,冒號,星號,問號,小于號,大于號,豎線之外的其他的任意字符,

然后是字符點,

然后以jpg,gif,png,bmp中的其中一個而結(jié)尾

而對應(yīng)的,由于之前還有flag標(biāo)志,表示忽略大小寫,則所匹配的內(nèi)容,就是上述內(nèi)容的表述,再加上一個,期間部分大小寫,就可以了。

所以,最終所要表述的含義就是:

去匹配一個字符串, 期間字母不分大小寫,

該字符串,開頭部分,就一個字母,該字母可能是從A到Z的任何一個字母,

后面跟著一個冒號,

再后面是1個或2個反斜杠,

然后是至少一個,但盡量多的,除了斜杠,冒號,星號,問號,小于號,大于號,豎線之外的其他的任意字符,

然后是字符點,

然后以jpg,gif,png,bmp中的其中一個而結(jié)尾

由此,我們可以隨便寫出來一個,符合該規(guī)則的字符串,比如:

a:\123abc.jpg

a:\\123abc.bmp

a:\\123abcdef.jpg

A:\\123abcdef.jpg

E:\\abc123.png

等等,諸如此類的字符串。

此時,已可很明顯看出來其用意了,其就是要去匹配:

Windows類系統(tǒng)(如XP,Win7等)中,本地的某個磁盤分區(qū)根目錄下的某張圖片而已。

至此,算是完整的,從開始的,無法用肉眼一眼就看出來含義的,那個復(fù)雜的,正則表達(dá)式,將其一點點拆分,分成多個子表達(dá)式,各個擊破其子表達(dá)式的含義,最終再把每個子表達(dá)式的含義合成在一起,再加上對應(yīng)的flag標(biāo)志的影響,最終生成了復(fù)雜表達(dá)式的最終含義,以及,用文字描述出來,最終,領(lǐng)悟和理解,原始的正則表達(dá)式,所要表示的含義。

通過此分析過程可見,其實再復(fù)雜的表達(dá)式,也都是可以通過拆分的方法,由繁化簡,而逐個擊破,了解細(xì)節(jié)的含義,再整合出宏觀上的整體的含義,最終搞懂完整的表達(dá)式的含義的。

只是過程,或繁或簡,取決于表達(dá)式本身的復(fù)雜程度,以及你本身所對正則表達(dá)式的理解和掌握的程度。

【總結(jié)】

千言萬語總結(jié)出幾句話:

1. 對于復(fù)雜的正則表達(dá)式,即使從左往右,一點點分析,拆分出多個子正則表達(dá)式,然后各個擊破,搞懂其含義,最后再合成一個總體的含義,即可實現(xiàn),將復(fù)雜的正則表達(dá)式,翻譯成人類可以讀懂的含義了。

2.再復(fù)雜的正則表達(dá)式,花足夠的時間去分析,都是能搞懂的。 只不過具體要花多長時間,則因人而異。

3.想要盡快的,準(zhǔn)確的理解原正則表達(dá)式所要描述的含義,還是要多多練習(xí),最終達(dá)到熟能生巧,以至于觸類旁通的效果。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多