元字符
注意匹配時(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?)
方法 功能
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’
捕獲(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’。
使用字符串方法?
有時(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$”)