Re 正則表達(dá)式

元字符

注意匹配時(shí)要匹配原始字符串,避免發(fā)生沖突 用 r”

. ^ $ * + ? {} [] () \ |

.匹配除換行符以外的任意字符

\w匹配字母或數(shù)字或下劃線或漢字

\s匹配任意的空白符

\d匹配數(shù)字

\b匹配單詞的開(kāi)始或結(jié)束

^匹配字符串的開(kāi)始,如果設(shè)置了MULTILINE標(biāo)志,就會(huì)變成匹配每一行開(kāi)始的位置

$匹配字符串的結(jié)束

[abc]匹配a或者d或者c[0-9]匹配0到9的數(shù)字,相當(dāng)于\d

*重復(fù)零次或更多次

+重復(fù)一次或更多次

?重復(fù)零次或一次

{n}重復(fù)n次

{n,}重復(fù)n次或更多次

{n,m}重復(fù)n到m次

\W匹配任意不是字母,數(shù)字,下劃線,漢字的字符

\S匹配任意不是空白符的字符

\D匹配任意非數(shù)字的字符

\B匹配不是單詞開(kāi)頭或結(jié)束的位置

[^x]匹配除了x以外的任意字符

[^aeiou]匹配除了aeiou這幾個(gè)字母以外的任意字符

一個(gè)IP:?

((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

實(shí)現(xiàn)方法

方法 功能

match()判斷一個(gè)正則表達(dá)式是否從開(kāi)始處匹配一個(gè)字符串

search()遍歷字符串,找到正則表達(dá)式匹配的第一個(gè)位置

findall()遍歷字符串,找到正則表達(dá)式匹配的所有位置,并以列表的形式返回

finditer()遍歷字符串,找到正則表達(dá)式匹配的所有位置,并以迭代器的形式返回

group()返回匹配的字符串

start()返回匹配的開(kāi)始位置

end()返回匹配的結(jié)束位置

span()返回一個(gè)元組表示匹配位置(開(kāi)始,結(jié)束)

編譯方式:

charref = re.compile(r”“”?

&[#] # 開(kāi)始數(shù)字引用?

(?

0[0-7]+ # 八進(jìn)制格式?

| [0-9]+ # 十進(jìn)制格式?

| x[0-9a-fA-F]+ # 十六進(jìn)制格式?

)?

; # 結(jié)尾分號(hào)?

“”“, re.VERBOSE)

分組

在正則表達(dá)式中,使用元字符 ( ) 來(lái)劃分組。?

使用 ( ) 表示的子組我們還可以對(duì)它進(jìn)行按層次索引,可以將索引值作為參數(shù)傳遞給這些方法:group(),start(),end() 和 span()。序號(hào) 0 表示第一個(gè)分組(這個(gè)是默認(rèn)分組,一直存在的,所以不傳入?yún)?shù)相當(dāng)于默認(rèn)值 0):?

eg?

>>>p = re.compile(r’(ab)cd’)?

>>>m = p.match(‘a(chǎn)bcde’)?

>>>m.group()?

>>>’abcd’?

>>>m.group(1)?

>>>’ab’?

子組的索引值是從左到右進(jìn)行編號(hào),子組也允許嵌套,因此我們可以通過(guò)從左往右來(lái)統(tǒng)計(jì)左括號(hào) ( 來(lái)確定子組的序號(hào)。?

1.>>> p = re.compile(‘(a(b)c)d’)?

2.>>> m = p.match(‘a(chǎn)bcd’)?

3.>>> m.group(0)?

4.’abcd’?

5.>>> m.group(1)?

6.’abc’?

7.>>> m.group(2)?

8.’b’?

group()?方法可以一次傳入多個(gè)子組的序號(hào):?

1.>>> m.group(2,1,2)?

2.(‘b’, ‘a(chǎn)bc’, ‘b’)?

我們還可以通過(guò)?groups()?方法一次性返回所有的子組匹配的字符串:?

1.>>> m.groups()?

2.(‘a(chǎn)bc’, ‘b’)?

反向引用:?

反向引用指的是你可以在后面的位置使用先前匹配過(guò)的內(nèi)容,用法是反斜杠加上數(shù)字。例如 \1 表示引用前邊成功匹配的序號(hào)為 1 的子組。?

1.>>> p = re.compile(r’(\b\w+)\s+\1’)?

2.>>> p.search(‘Paris in the the spring’).group()?

3.’the the’

擴(kuò)展語(yǔ)法:(?…))

捕獲(exp)匹配exp,并捕獲文本到自動(dòng)命名的組里

(?<name>exp)匹配exp,并捕獲文本到名稱為name的組里,也可以寫(xiě)成(?’name’exp)

(?:exp)匹配exp,不捕獲匹配的文本,也不給此分組分配組號(hào)

零寬斷言(?=exp)匹配exp前面的位置

(?<=exp)匹配exp后面的位置

(?!exp)匹配后面跟的不是exp的位置

(?< !exp)匹配前面不是exp的位置

注釋 (?#comment) 這種類型的分組不對(duì)正則表達(dá)式的處理產(chǎn)生任何影響,用于提供注釋讓人閱讀?

非捕獲組:?

有時(shí)候你知識(shí)需要用一個(gè)組來(lái)表示部分正則表達(dá)式,你并不需要這個(gè)組去匹配任何東西,這時(shí)你可以通過(guò)非捕獲組來(lái)明確表示你的意圖。非捕獲組的語(yǔ)法是 (?:…),這個(gè) … 你可以替換為任何正則表達(dá)式。?

eg:?

/>>> p = re.compile(r’(?:ab)(c)d’)?

/>>> m = p.match(‘a(chǎn)bcde’)?

/>>> m.groups()?

(‘c’,)?

命名組:?

我們?cè)賮?lái)看另外一個(gè)重要功能:命名組。普通子組我們使用序列來(lái)訪問(wèn)它們,命名組則可以使用一個(gè)有意義的名字來(lái)進(jìn)行訪問(wèn)。

命名組的語(yǔ)法是 Python 特有的擴(kuò)展語(yǔ)法:(?P)。很明顯,< > 里邊的 name 就是命名組的名字啦。命名組除了有一個(gè)名字標(biāo)識(shí)之外,跟其他捕獲組是一樣的。

匹配對(duì)象的所有方法不僅可以處理那些由數(shù)字引用的捕獲組,還可以處理通過(guò)字符串引用的命名組。除了使用名字訪問(wèn),命名組仍然可以使用數(shù)字序號(hào)進(jìn)行訪問(wèn):?

1.>>> p = re.compile(r’(?P\b\w+\b)’)?

2.>>> m = p.search( ‘(((( Lots of punctuation )))’ )?

3.>>> m.group(‘word’)?

4.’Lots’?

5.>>> m.group(1)?

6.’Lots’

正則表達(dá)式中,反向引用的語(yǔ)法像 (…)\1 是使用序號(hào)的方式來(lái)訪問(wèn)子組;在命名組里,顯然也是有對(duì)應(yīng)的變體:使用名字來(lái)代替序號(hào)。其擴(kuò)展語(yǔ)法是 (?P=name),含義是該 name 指向的組需要在當(dāng)前位置再次引用。那么搜索兩個(gè)單詞的正則表達(dá)式可以寫(xiě)成 (\b\w+)\s+\1,也可以寫(xiě)成 (?P\b\w+)\s+(?P=word):?

1.>>> p = re.compile(r’(?P\b\w+)\s+(?P=word)’)?

2.>>> p.search(‘Paris in the the spring’).group()?

3.’the the’?

前向斷言

另一個(gè)零寬斷言,前向斷言,前向斷言可以分為前向肯定斷言和前向否定斷言兩種形式。

(?=…)?

前向肯定斷言。如果當(dāng)前包含的正則表達(dá)式(這里以 … 表示)在當(dāng)前位置成功匹配,則代表成功,否則失敗。一旦該部分正則表達(dá)式被匹配引擎嘗試過(guò),就不會(huì)繼續(xù)進(jìn)行匹配了;剩下的模式在此斷言開(kāi)始的地方繼續(xù)嘗試。

(?!…)?

前向否定斷言。這跟前向肯定斷言相反(不匹配則表示成功,匹配表示失?。?

一個(gè)簡(jiǎn)單的正則表達(dá)式模式,這個(gè)模式的作用是匹配一個(gè)文件名。文件名是用 . 將名字和擴(kuò)展名分隔開(kāi)的。例如在 shi.txt 中,fishc 是文件的名字,.txt 是擴(kuò)展名。

這個(gè)正則表達(dá)式其實(shí)挺簡(jiǎn)單的:

.*[.].*$

注意,這里用于分隔的 . 是一個(gè)元字符,所以我們使用 [.] 剝奪了它的特殊功能。還有?,我們使用?確保字符串剩余的部分都包含在擴(kuò)展名中。所以這個(gè)正則表達(dá)式可以匹配 shi.txt,foio.bar,auc.bat,osoenl.cf,print.conf 等。

現(xiàn)在我們來(lái)考慮一種復(fù)雜一點(diǎn)的情況,如果你想匹配擴(kuò)展名不是 bat 的文件,你的正則表達(dá)式應(yīng)該怎么寫(xiě)呢??

有可能寫(xiě)錯(cuò)的嘗試:?

.*[.][^b].*$

為了排除 bat,先排除擴(kuò)展名的第一個(gè)字符為非 b。但這是錯(cuò)誤的,因?yàn)?foio.bar 后綴名的第一個(gè)字符也是 b。

彌補(bǔ)剛剛的錯(cuò)誤:

.*[.]([^b]..|.[^a].|..[^t])$

這樣第一個(gè)字符不是 b,第二個(gè)字符不是 a,第三個(gè)字符不是 t……這樣正好可以接受 foo.bar,排除 autoexec.bat。但問(wèn)題又來(lái)了,這樣的正則表達(dá)式要求擴(kuò)展名必須是三個(gè)字符,比如 sel.cf 就會(huì)被排除掉。

我們接著修復(fù)問(wèn)題:

.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$

在第三次嘗試中,讓第二個(gè)和第三個(gè)字符變成可選的。這樣就可以匹配稍短的擴(kuò)展名,比如 sel.cf。更慘的是如果需求改變了,例如你想同時(shí)排除 bat 和 exe 擴(kuò)展名,這個(gè)正則表達(dá)式模式就變得更加復(fù)雜了……

其實(shí),一個(gè)前向否定斷言就可以解決:

.*[.](?!bat$).*$

解釋一下這個(gè)前向否定斷言的含義:如果正則表達(dá)式 bat 在當(dāng)前位置不匹配,嘗試剩下的部分正則表達(dá)式;如果 bat 匹配成功,整個(gè)正則表達(dá)式將會(huì)失?。ㄒ?yàn)槭乔跋蚍穸〝嘌裕??!bat$) 末尾的 $ 是為了確??梢哉Fヅ湎?sam.bat7h 這種以 bat 開(kāi)始的擴(kuò)展名。

同樣,有了前向否定斷言,要同時(shí)排除 bat 和 exe 擴(kuò)展名,也變得相當(dāng)容易:

.*[.](?!bat$|exe$).*$

修改字符串

split()在正則表達(dá)式匹配的地方進(jìn)行分割,并返回一個(gè)列表

sub()找到所有匹配的子字符串,并替換為新的內(nèi)容

subn()跟 sub() 一樣,但返回新的字符串以及替換的數(shù)目

eg:?

正則表達(dá)式的 split() 方法將字符串在匹配的地方進(jìn)行分割,并將分割后的結(jié)果作為列表返回。它的做法其實(shí)很像字符串的 split() 方法,但這個(gè)可以使用更加廣泛的分隔符。它同時(shí)提供了一個(gè)模塊級(jí)別的函數(shù):re.split()

.split(string[, maxsplit=0])?

通過(guò)正則表達(dá)式匹配來(lái)分割字符串。如果在 RE 中,你使用了捕獲組,那么它們的內(nèi)容會(huì)作為一個(gè)列表返回。你可以通過(guò)傳入一個(gè) maxsplit 參數(shù)來(lái)設(shè)置分割的數(shù)量。如果 maxsplit 的值是非 0,表示至多有 maxsplit 個(gè)分割會(huì)被處理,剩下的內(nèi)容作為列表的最后一個(gè)元素返回。

下邊例子中,分隔符是任何非字母數(shù)字字符:?

1.>>> p = re.compile(r’\W+’)?

2.>>> p.split(‘This is a test, short and sweet, of split().’)?

3.[‘This’, ‘is’, ‘a(chǎn)’, ‘test’, ‘short’, ‘a(chǎn)nd’, ‘sweet’, ‘of’, ‘split’, ”]?

4.>>> p.split(‘This is a test, short and sweet, of split().’, 3)?

5.[‘This’, ‘is’, ‘a(chǎn)’, ‘test, short and sweet, of split().’]

如果使用了捕獲組,那么作為分隔符的值也會(huì)被返回?

1.>>> p = re.compile(r’\W+’)?

2.>>> p2 = re.compile(r’(\W+)’)?

3.>>> p.split(‘This… is a test.’)?

4.[‘This’, ‘is’, ‘a(chǎn)’, ‘test’, ”]?

5.>>> p2.split(‘This… is a test.’)?

6.[‘This’, ‘… ‘, ‘is’, ’ ‘, ‘a(chǎn)’, ’ ‘, ‘test’, ‘.’, ”]

模塊級(jí)別的函數(shù) re.split() 除了將 RE 作為第一個(gè)參數(shù)外,其他參數(shù)是一樣的:?

1.>>> re.split(‘[\W]+’, ‘Words, words, words.’)?

2.[‘Words’, ‘words’, ‘words’, ”]?

3.>>> re.split(‘([\W]+)’, ‘Words, words, words.’)?

4.[‘Words’, ‘, ‘, ‘words’, ‘, ‘, ‘words’, ‘.’, ”]?

5.>>> re.split(‘[\W]+’, ‘Words, words, words.’, 1)?

6.[‘Words’, ‘words, words.’]?

搜索和替換:?

另一個(gè)常見(jiàn)的任務(wù)就是找到所有的匹配部分,并替換成不同的字符串。sub 方法可以實(shí)現(xiàn)!sub 方法有一個(gè) replacement 參數(shù),它可以是一個(gè)待替換的字符串,或者一個(gè)處理字符串的函數(shù)。

.sub(replacement, string[, count=0])?

返回一個(gè)字符串,這個(gè)字符串從最左邊開(kāi)始,所有 RE 匹配的地方都替換成 replacement。如果沒(méi)有找到任何匹配,那么返回原字符串。?

可選參數(shù) count 指定最多替換的次數(shù),必須是一個(gè)非負(fù)值。默認(rèn)值是 0,意思是替換所有找到的匹配。

下邊是使用 sub() 方法的例子,它會(huì)將所有的顏色替換成 color:?

1.>>> p = re.compile( ‘(blue|white|red)’)?

2.>>> p.sub( ‘colour’, ‘blue socks and red shoes’)?

3.’colour socks and colour shoes’?

4.>>> p.sub( ‘colour’, ‘blue socks and red shoes’, count=1)?

5.’colour socks and red shoes’

subn() 方法跟 sub() 方法干同樣的勾當(dāng),但區(qū)別是返回值為一個(gè)包含有兩個(gè)元素的元組:一個(gè)是替換后的字符串,一個(gè)是替換的數(shù)目。?

1.>>> p = re.compile( ‘(blue|white|red)’)?

2.>>> p.subn( ‘colour’, ‘blue socks and red shoes’)?

3.(‘colour socks and colour shoes’, 2)?

4.>>> p.subn( ‘colour’, ‘no colours at all’)

如果 replacement 參數(shù)是一個(gè)字符串,那么里邊的反斜杠都會(huì)被處理。比如 \n 將會(huì)被轉(zhuǎn)換成一個(gè)換行符,\r 轉(zhuǎn)換成回車,等等。未知的轉(zhuǎn)義如 \j 保持原樣。逆向引用如 \6,則被 RE 中相應(yīng)的捕獲組匹配的內(nèi)容所替換。這使你可以在替換后的字符串中插入一部分原字符串。?

下邊例子中,將匹配被 { 和 } 括起來(lái)的單詞 section,并將 section 替換成 subsection:?

1.>>> p = re.compile(‘section{ ( [^}]* ) }’, re.VERBOSE)?

2.>>> p.sub(r’subsection{\1}’,’section{First} section{second}’)?

3.’subsection{First} subsection{second}’?

解釋:1. 這里開(kāi)啟了 re.VERBOSE,空格將被忽略。因?yàn)檫@里一堆符號(hào),用空格隔開(kāi)看著才不會(huì)亂糟糟的……2. 這里 r’subsection{\1}’ 使用 \1 引用匹配模式中的 ([^}]*) 匹配的字符串內(nèi)容。

還可以使用?Python 的擴(kuò)展語(yǔ)法 (?P<*name>…) 指定命名組,引用命名組的語(yǔ)法是 \g<name>。\g<name> 會(huì)將名字為 name 的組匹配的字符串替換進(jìn)去。另外,\g<數(shù)字> 是通過(guò)組的序號(hào)進(jìn)行引用。\g<2> 其實(shí)就相當(dāng)于 \2,但我們更提倡使用 \g<2>,因?yàn)檫@樣可以避免歧義。例如,\g<2>0 的含義是引用序號(hào)為 2 的組,然后后邊匹配一個(gè)字符 ‘0’,而你寫(xiě)成 \20 就會(huì)被認(rèn)為是引用序號(hào)為 20 的組了。?

1.>>> p = re.compile(‘section{ (?P<name> [^}]* ) }’, re.VERBOSE)?

2.>>> p.sub(r’subsection{\1}’,’section{First}’)?

3.’subsection{First}’?

4.>>> p.sub(r’subsection{\g<1>}’,’section{First}’)?

5.’subsection{First}’?

6.>>> p.sub(r’subsection{\g<name>}’,’section{First}’)?

7.’subsection{First}’

有時(shí)候可能不滿足簡(jiǎn)單的字符串替換,replacement 參數(shù)還可以是一個(gè)函數(shù),該函數(shù)將會(huì)在正則表達(dá)式模式每次不重復(fù)匹配的時(shí)候被調(diào)用。在每次調(diào)用時(shí),函數(shù)會(huì)收到一個(gè)匹配對(duì)象的參數(shù),因此你就可以利用這個(gè)對(duì)象去計(jì)算出新的字符串并返回它。

下邊的例子中,替換函數(shù)將十進(jìn)制數(shù)替換為十六進(jìn)制數(shù):?

1.>>> def hexrepl(match):?

2…. “Return the hex string for a decimal number”?

3…. value = int(match.group())?

4…. return hex(value)?

5….?

6.>>> p = re.compile(r’\d+’)?

7.>>> p.sub(hexrepl, ‘Call 65490 for printing, 49152 for user code.’)?

8.’Call 0xffd2 for printing, 0xc000 for user code.’

當(dāng)使用模塊級(jí)的 re.sub() 函數(shù)時(shí),正則表達(dá)式模式作為第一個(gè)參數(shù)。該模式可以是一個(gè)字符串或一個(gè)編譯好的對(duì)象。如果你需要指定正則表達(dá)式標(biāo)志,那么你必須使用后者;或者使用模式內(nèi)嵌修正器,例如 sub(“(?i)b+”, “x”, “bbbb BBBB”) 返回 ‘x x’。

注意事項(xiàng):

使用字符串方法?

有時(shí)使用 re 模塊是個(gè)錯(cuò)誤!如果你匹配一個(gè)固定的字符串或者單個(gè)字符類,并且你沒(méi)有使用 re 的任何標(biāo)志(像 IGNORECASE 標(biāo)志),那么就沒(méi)有必要使用正則表達(dá)式了。字符串有一些方法是對(duì)固定字符串進(jìn)行操作的,并且它們通常比較快。因?yàn)樗鼈兌际仟?dú)立優(yōu)化的 C 語(yǔ)言小循環(huán),目的是在簡(jiǎn)單的情況下代替功能更加強(qiáng)大、更具通用性的正則表達(dá)式引擎。?

舉個(gè)例子,例如你想把字符串中所有的 dead 替換成 word,你會(huì)想到使用正則表達(dá)式的 re.sub() 方法來(lái)實(shí)現(xiàn),但這么簡(jiǎn)單的替換,還是考慮直接使用字符串的 replace() 方法吧。但有一點(diǎn)你需要注意,就是 replace() 會(huì)在單詞里邊進(jìn)行替換,像 swordfish 會(huì)變成 sdeedfish,這顯然不是你想要的!replace() 沒(méi)辦法識(shí)別單詞的邊界,因此你才來(lái)考慮使用正則表達(dá)式。只需要將 RE 的模式寫(xiě)成 \bword\b 即可勝任此任務(wù)。?

另一個(gè)常見(jiàn)的情況是從一個(gè)字符串中刪除單個(gè)字符或者用另一個(gè)字符替代它。你也許會(huì)想到用 re.sub(‘\n’, ’ ‘, S) 這樣的正則表達(dá)式來(lái)實(shí)現(xiàn),但其實(shí)字符的 translate() 方法完全能夠勝任這個(gè)任務(wù),并且比任何正則表達(dá)式操作起來(lái)更快些。?

簡(jiǎn)而言之,在使用 re 模塊之前,先考慮一下你的問(wèn)題是否可以用更快速、簡(jiǎn)單的字符串自帶方法來(lái)解決。

match() VS search()?

match() 函數(shù)只會(huì)檢查 RE 是否在字符串的開(kāi)始處匹配,而 search() 會(huì)遍歷整個(gè)字符串搜索匹配的內(nèi)容。記住這一區(qū)別很重要。再次強(qiáng)調(diào)一下,match() 只會(huì)報(bào)告一次成功的匹配,并且匹配的位置必須是從字符串的第一個(gè)字符開(kāi)始:?

1.>>> print(re.match(‘super’, ‘superstition’).span())?

2.(0, 5)?

3.>>> print(re.match(‘super’, ‘insuperable’))?

4.None?

另一方面,search() 函數(shù)將遍歷整個(gè)字符串,并報(bào)告它找到的第一個(gè)匹配:?

1.>>> print(re.search(‘super’, ‘superstition’).span())?

2.(0, 5)?

3.>>> print(re.search(‘super’, ‘insuperable’).span())?

4.(2, 7)?

一般分析會(huì)先找到匹配的第一個(gè)字符是什么。舉個(gè)例子,模式 Crow 必須從字符 ‘C’ 開(kāi)始匹配,那么匹配引擎分析后會(huì)快速遍歷字符串,然后在 ‘C’ 被找到之后才開(kāi)始全部匹配。?

添加一個(gè) .* 會(huì)導(dǎo)致這個(gè)優(yōu)化失敗,請(qǐng)使用 re.search() 代替。

貪婪 VS 非貪婪?

當(dāng)重復(fù)一個(gè)正則表達(dá)式時(shí),如果使用 a*,那么結(jié)果是盡可能多地去匹配。當(dāng)你嘗試匹配一對(duì)對(duì)稱的定界符,例如 HTML 標(biāo)志中的尖括號(hào),默認(rèn)的貪婪模式會(huì)使得你很困擾。?

eg:?

1.>>> s = ‘<html><head><title>Title</title>’?

2.>>> len(s)?

3.32?

4.>>> print(re.match(‘<.*>’, s).span())?

5.(0, 32)?

6.>>> print(re.match(‘<.*>’, s).group())?

7.<html><head><title>Title</title>?

RE 匹配在 <html> 的 < 后,.*?消耗掉字符串的剩余部分。由于正則表達(dá)式默認(rèn)是貪婪的原因,RE 必須從字符串的尾部一個(gè)字符一個(gè)字符地回溯,直到找到匹配的 >。大家看到,按照這種方法,最后找到匹配內(nèi)容竟是 的 < 開(kāi)始,到 的 > 結(jié)束。顯然這不是你想要的結(jié)果。?

在這種情況下,解決方案是使用非貪婪的限定符 *?、+?、?? 或 {m,n}?,盡可能地匹配小的文本。?

1.>>> print(re.match(‘<.*?>’, s).group())?

2.<html>?

在上邊的例子中,> 在第一個(gè) < 被匹配后立刻嘗試匹配,如果失敗,匹配引擎前進(jìn)一步,嘗試下一個(gè)字符,直到第一次匹配 >,這樣就得到了我們想要的結(jié)果。?

注意,使用正則表達(dá)式分析 HTML 和 XML 是很痛苦的。當(dāng)你編寫(xiě)一個(gè)正則表達(dá)式去處理所有可能的情況時(shí),你會(huì)發(fā)現(xiàn) HTML 和 XML 總會(huì)打破你的“規(guī)則”,這讓你很頭疼……像這樣的話,建議使用 HTML 和 XML 解析器來(lái)處理更合適。?

re的貪婪模式會(huì)盡可能多的匹配

使用 re.VERBOSE?

正則表達(dá)式的表示非常緊湊。這也帶來(lái)了一個(gè)問(wèn)題,就是不好閱讀。當(dāng)編譯正則表達(dá)式時(shí)指定 re.VERBOSE 標(biāo)志是非常有幫助的?

re.VERBOSE 標(biāo)志有幾個(gè)作用。在正則表達(dá)式中不在字符類中的空白字符將被忽略。這就意味著像 I love FishC 這樣的表達(dá)式和可讀性較差的 IloveFishC 相同。但 [a b] 將匹配字符 ‘a(chǎn)’、’b’ 或 ’ ‘;另外,你也可以把注釋放到 RE 中,注釋是從 # 開(kāi)始到下一行。當(dāng)使用三引號(hào)字符串時(shí),會(huì)使得 REs 的格式更整潔:?

pat = re.compile(r”“”?

\s* # Skip leading whitespace?

(?P<header>[^:]+) # Header name?

\s* : # Whitespace, and a colon?

(?P<value>.?) # The header’s value –?? used to?

# lose the following trailing whitespace?

\s*$ # Trailing whitespace to end-of-line?

“”“, re.VERBOSE)?

同樣的內(nèi)容,下邊這個(gè)要難讀得多:

pat = re.compile(r”\s*(?P<header>[^:]+)\s*:(?P<value>.*?)\s$”)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容