由淺到深解讀Python正則表達(dá)式
對于許多需要處理文本來說的技術(shù)工程師,必須對Python正則表達(dá)式有一個全面深入的認(rèn)識,不但要深入理解下什么是Python正則表達(dá)式,還要對Python正則表達(dá)式字符有所認(rèn)識。
此外,還有少數(shù)字符比較特殊,它們和自身并不匹配,而是跟其字面值之外的一些特殊的東西匹配,這些東西可能是字符集、重復(fù)次數(shù)或者位置等。常用的元字符包括:
. ^ $ * + ? { } [ ] \ | ( )
對于這些特殊字符,本文會陸續(xù)加以介紹。不過我們這里先了解一下用來匹配字符的元字符。首先,句點“.”這個元字符通常用于想匹配“任何字符”的地方:一般情況下,它匹配除換行字符之外的任何字符;但是在alternate模式(re.DOTALL)下,它匹配真正意義上的任何字符,包括換行字符在內(nèi)。
我們接下來考察的元字符是“[”和“]”。它們常配對用來指定想匹配的一個字符集合,也就是說該集合內(nèi)的任何一個元素都能滿足我們的要求。集合內(nèi)的字符可以單個列出,如果這些字符是連續(xù)的也可以用“-”號分隔的兩個給定字符來指定一個字符范圍。
例如,[abc]將匹配“a”、“b”或“c”中的任意一個字符;當(dāng)然也可以用區(qū)間[a-c]來表示同一字符集,這兩者表示方法是等效的。如果想匹配字符串中的所有元音字母,則可使用下列代碼:
- import re
- def re_show(pat, s):
- print re.compile(pat, re.M).sub("{\g<0>}", s.rstrip()),'\n'
- s = '''In company or association with respect to place or time;
- as, to live together in one house; to live together in the
- same age; they walked together to the town.'''
- re_show(r"[aeiou]",s)
運(yùn)行結(jié)果如下所示:
- In c{o}mp{a}ny {o}r {a}ss{o}c{i}{a}t{i}{o}n w{i}th r{e}sp{e}ct t{o} pl{a}c{e} {o}r t{i}m{e};
- {a}s, t{o} l{i}v{e} t{o}g{e}th{e}r {i}n {o}n{e} h{o}{u}s{e}; t{o} l{i}v{e} t{o}g{e}th{e}r {i}n th{e}
- s{a}m{e} {a}g{e}; th{e}y w{a}lk{e}d t{o}g{e}th{e}r t{o} th{e} t{o}wn.
對于字符集合有一點需要特別注意,就是元字符在方括號中會“降級”為普通字符。例如,[a.]將匹配字符“a”或“.”中的任意一個;前面說過“.”通常用作元字符。但在字符集合里,其特殊性將被剝奪,恢復(fù)成普通字符。這一點讀者可以自己改動一下上面的代碼來實驗一下。
有時需要查找不屬于某個字符集合的字符。比如想查找除了數(shù)字6以外,其它任意字符都行的情況,這時需要用到反義:其做法是把元字符“^”作為集合的***字符,例如,[^5] 將匹配除“6”之外的任意字符。
反斜杠“\”是一種非常重要的元字符。我們知道在Python的字符串中,反斜杠也是作為一種特殊字符(或轉(zhuǎn)義字符)使用,后面可以跟不同的字符以表示不同特殊意義;它也可以用于取消所有的元字符,這樣你就可以在模式中匹配它們了。舉個例子,如果你需要匹配字符“\”,你可以在其之前用反斜杠來取消它們的特殊意義:\\。#t#
◆\d 匹配任何十進(jìn)制數(shù);它等價于字符集合[0-9]。
◆\D 匹配任何非數(shù)字字符;它等價于字符集合[^0-9]。
◆\s 匹配任何空白字符;它等價于字符集合[ \t\n\r\f\v]。
◆\S 匹配任何非空白字符;它等價于字符集合[^ \t\n\r\f\v]。
◆\w 匹配任何字母數(shù)字下劃線字符;它等價于字符集合[a-zA-Z0-9_]。
◆\W 匹配任何非字母數(shù)字下劃線字符;它等價于字符集合[^a-zA-Z0-9_]。
我們已經(jīng)講過為單個字符指定重復(fù)次數(shù)的方法——直接在字符后面加上限定符就行了;現(xiàn)在我們再來學(xué)習(xí)一下重復(fù)多個字符的八法:你可以用小括號來指定子表達(dá)式(也叫做分組),然后你就可以指定這個子表達(dá)式的重復(fù)次數(shù)了,你也可以對子表達(dá)式進(jìn)行其它一些操作。
我們知道,IP地址是由點號分隔的四個數(shù)字,并且每個數(shù)字都不能大于255。(\d{1,3}\.){3}\d{1,3}是一個簡單的IP地址匹配表達(dá)式,其中:\d{1,3}匹配1到3位的數(shù)字,(\d{1,3}\.){3}匹配三位數(shù)字加上一個英文句號(這個整體也就是這個分組)重復(fù)3次,***再加上一個一到三位的數(shù)字(\d{1,3})。
然而,它也將匹配256.300.888.999這種不可能存在的IP地址。如果能使用算術(shù)比較的話,或許能簡單地解決這個問題,但是正則表達(dá)式中并不提供關(guān)于數(shù)學(xué)的任何功能,所以只能使用冗長的分組。
選擇Python正則表達(dá)式和字符集合來描述一個正確的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。理解這個表達(dá)式的關(guān)鍵是理解2[0-4]\d|25[0-5]|[01]?\d\d?,經(jīng)過上面的介紹,相信讀者能分析得出來它的意義。