如何教你看懂復雜的正則表達式


【前言】

1.此文針對,正則表達式的初學者,老鳥請飄過。

正則表達式的初學者,常遇到的情況是,對於相對復雜一點的正則表達式,覺得很難理解,很難看懂。

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

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

3.在看此文之前,肯定需要你本身對於正則表達式,已經有了一些基本的基礎,

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

 

關於正則表達式方面的教程和資料,需要的可以去看我整理的一些資料:

正則表達式學習心得

【教程】詳解Python正則表達式

【總結】關於(C#和Python中的)正則表達式

java中的正則表達式:java.util.regex

 

【如何看懂復雜的正則表達式】

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

解釋:

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

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

每個小塊的正則表達式都搞懂后

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

最后就可以實現,用人類的語言,把對應的復雜的正則表達式,一點點解釋出來了,即:

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

 

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

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

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

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

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

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

 

【舉例說明,如何實現拆分復雜的正則表達式】

舉例:

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

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

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

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

/xxx/i

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

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

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

其中的xxx,是此處真正的正則表達式:

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

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

 

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

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

的完整的含義:

對於我來說,看到此正則表達式:

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

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

先說拆分的結果如下:

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

 

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

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

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

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

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

 

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

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

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

1 ^

 

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

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

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

而作為比你經驗稍多的我,要告訴你,其實你此處這樣的想法,是嚴謹的,因為,對於,中括號內部表示字符集合,[xxx]的寫法,往往后面還會跟着一些限定符,去表示此集合字符的個數方面的限定,比如加號’+’表示去匹配,往后數,盡可能多個,比如表示最少2個,最多5個的'{2,5}’等等。

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

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

1 ^
2 [A-Z]

 

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

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

1 ^
2 [A-Z]
3 :

 

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

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

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

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

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

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

 

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

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

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

^/:\*\?<>\|

至少看起來,也還是比較復雜的。

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

而此處,就是對應的

對於

/:\*\?<>\|

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

^/:\*\?<>\|

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

/:\*\?<>\|

之外的字符。

而此處的字符組合:

/:\*\?<>\|

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

 

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

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

 

因此,此處已經共分析出5個子表達式了:

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

 

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

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

在正則表達式中,常見的就有:

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

 

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

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

 

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

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

(jpg|gif|png|bmp)

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

而對於此處的group組:

(jpg|gif|png|bmp)

的含義,后面再詳細分析。

此時,也已經拆分出來,共7個子表達式了:

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

 

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

此時,就已經實現了,把上述的一個復雜的正則表達式,拆分成多個邏輯上獨立的,共8個,子正則表達式了:

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

 

 

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

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

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

 

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

下面先來總結一下,已經知道的,各個子表達式的含義:

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

 

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

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

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

/:\*\?<>\|

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

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

此處,根據字符本身含義,依次是:

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

 

所以,此部分

 

的總體含義就是:

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

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

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

的意思就是

除了字符:

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

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

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

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

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

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

除了字符:

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

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

 

到此,對此

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

的含義,才算基本明確。

而如果你本身對於windows等操作系統對於文件名或者路徑字符的限制有了解的話,你會發現,這基本上就是

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

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

即:

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

 

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

 

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

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

xxx|xxx|xxx

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

對應的,其所表達的意思是,去匹配:

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

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

 

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

【教程】詳解Python正則表達式之: ‘|’ vertical bar 豎杠

 

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

子正則表達式序號 子正則表達式內容 子正則表達式的含義
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 $ 匹配正則表達式的末尾

 

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

去匹配一個字符串,

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

后面跟着一個冒號,

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

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

然后是字符點,

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

 

而對應的,由於之前還有flag標志,表示忽略大小寫,則所匹配的內容,就是上述內容的表述,再加上一個,期間部分大小寫,就可以了。

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

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

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

后面跟着一個冒號,

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

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

然后是字符點,

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

 

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

a:\123abc.jpg

a:\\123abc.bmp

a:\\123abcdef.jpg

A:\\123abcdef.jpg

E:\\abc123.png

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

 

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

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

 

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

 

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

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

 

【總結】

千言萬語總結出幾句話:

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

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

3.想要盡快的,准確的理解原正則表達式所要描述的含義,還是要多多練習,最終達到熟能生巧,以至於觸類旁通的效果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM