這篇文章,并不是對(duì)正則表達(dá)式的介紹,而是對(duì)Python中如何結(jié)合re模塊使用正則表達(dá)式的介紹。文章的側(cè)重點(diǎn)是如何使用re模塊在Python語(yǔ)言中使用正則表達(dá)式,對(duì)于Python表達(dá)式的語(yǔ)法和詳細(xì)的介紹,可以參考別的文章,這篇文章只是給出一些常用的正則表達(dá)式語(yǔ)法,以方便對(duì)re模塊的使用進(jìn)行講解。
對(duì)正則表達(dá)式的介紹,可以參看這兩篇文章:
注意:實(shí)驗(yàn)環(huán)境為 Python 3.4.3
正則表達(dá)式,又稱正規(guī)表示式、正規(guī)表示法、正規(guī)表達(dá)式、規(guī)則表達(dá)式、常規(guī)表示法(英語(yǔ):Regular ExPRession,在代碼中常簡(jiǎn)寫為regex、regexp或RE),計(jì)算機(jī)科學(xué)的一個(gè)概念。正則表達(dá)式使用單個(gè)字符串來(lái)描述、匹配一系列符合某個(gè)句法規(guī)則的字符串。在很多文本編輯器里,正則表達(dá)式通常被用來(lái)檢索、替換那些符合某個(gè)模式的文本。
許多程序設(shè)計(jì)語(yǔ)言都支持利用正則表達(dá)式進(jìn)行字符串操作。例如,在Perl中就內(nèi)建了一個(gè)功能強(qiáng)大的正則表達(dá)式引擎。正則表達(dá)式這個(gè)概念最初是由Unix中的工具軟件(例如sed和grep)普及開的。正則表達(dá)式通常縮寫成“regex”,單數(shù)有regexp、regex,復(fù)數(shù)有regexps、regexes、regexen。
最初的正則表達(dá)式出現(xiàn)于理論計(jì)算機(jī)科學(xué)的自動(dòng)控制理論和形式化語(yǔ)言理論中。在這些領(lǐng)域中有對(duì)計(jì)算(自動(dòng)控制)的模型和對(duì)形式化語(yǔ)言描述與分類的研究。 1940年,Warren McCulloch與Walter Pitts將神經(jīng)系統(tǒng)中的神經(jīng)元描述成小而簡(jiǎn)單的自動(dòng)控制元。 1950年代,數(shù)學(xué)家斯蒂芬·科爾·克萊尼利用稱之為“正則集合”的數(shù)學(xué)符號(hào)來(lái)描述此模型。肯·湯普遜將此符號(hào)系統(tǒng)引入編輯器QED,然后是Unix上的編輯器ed,并最終引入grep。自此,正則表達(dá)式被廣泛地使用于各種Unix或者類似Unix的工具,例如Perl。
Python提供了對(duì)正則表達(dá)式的支持,它內(nèi)嵌在Python中,通過(guò)Python的re模塊提供。
re模塊提供了類似于Perl的正則表達(dá)式語(yǔ)法。
通過(guò)使用正則表達(dá)式,我們可以制定需要匹配的字符串的特定格式,然后從需要處理的字符串中提取我們感興趣的字符串。Python中的re模塊也提供了像sub(),subn(),split()這些方法來(lái)實(shí)現(xiàn)通過(guò)正則表達(dá)式來(lái)靈活地進(jìn)行文本的替換和分割。
在Python中,正則表達(dá)式會(huì)被編譯成一系列的字節(jié)碼,然后由通過(guò)C編寫的正則表達(dá)式引擎進(jìn)行執(zhí)行。
下面,我們先看看正則表達(dá)是什么,了解下正則表達(dá)式是怎么處理字符串問(wèn)題的。如果你以前沒(méi)有接觸過(guò)正則表達(dá)式,是正則表達(dá)式小白,那么可以初略的熟悉下這節(jié)內(nèi)容,心里有個(gè)大概的了解。在接下來(lái)的幾節(jié)中,我們將學(xué)習(xí)到正則表達(dá)式的一些知識(shí),等學(xué)習(xí)完了有關(guān)正則的知識(shí),可以再回過(guò)頭來(lái)看看這些例子,加深下理解。
下面,我們簡(jiǎn)單的看看在Python中使用正則表達(dá)式的例子:
簡(jiǎn)答的字符串匹配操作
>>> import re >>> p = re.compile(r'ab*') >>> m = p.search('abbbba') >>> m.group() 'abbbb' >>> import re >>> p = re.compile(r'(ab)*') >>> m = p.search('abababa') >>> m.group(0) 'ababab'找出字符串中的數(shù)字
>>> import re >>> p = re.compile(r'/d+') >>> m = p.search('this year is 2015') >>> m.group() '2015'找出字符串中的字符
>>> import re >>> p = re.compile(r'/w+') >>> m = p.search('this year is 2015') >>> m.group() 'this'匹配郵箱地址
>>> p = re.compile(r'[/w/d]+@/w+/.com') >>> m = p.search('mymail@mail.com') >>> m.group() 'mymail@mail.com'匹配ip地址
>>> p = re.compile(r'(/d{1,3}/.){3}/d{1,3}') >>> m = p.search('ip address is : 192.168.1.1 not 192.1.1') >>> m.group() '192.168.1.1'大多數(shù)的字符在進(jìn)行正則表達(dá)式匹配的時(shí)候,會(huì)簡(jiǎn)單的進(jìn)行一對(duì)一的匹配,比如,普通的字符串test將會(huì)精確地匹配到test。但是,則正則表達(dá)式中,有一些字符具有特殊的用于,它們?cè)谄ヅ涞臅r(shí)候不會(huì)精確匹配到對(duì)應(yīng)的字符。這些具有特殊用于的字符,在正則表達(dá)式中被稱為元字符。
元字符不會(huì)匹配自身,相反,單個(gè)的元字符可以匹配不同內(nèi)容和長(zhǎng)度的字符串,或者影響正則表達(dá)式的執(zhí)行。正是由于元字符的存在,才使得正則表達(dá)式如此靈活和強(qiáng)大。
在正則表達(dá)式中,元字符由一些這些字符組成,這些字符在使用的時(shí)候不再表示它們?cè)瓉?lái)的作用,如果要使用它們?cè)瓉?lái)的意思,則需要使用反斜杠轉(zhuǎn)義:
. ^ $ * + ? { } [ ] / | ( )下面,我們將會(huì)正則表達(dá)式中的這些元字符進(jìn)行解釋,但是在這之前,我們需要先介紹下在Python中使用反斜杠進(jìn)行轉(zhuǎn)義時(shí)碰到的問(wèn)題。
在Python的字符串中,一些特殊的轉(zhuǎn)義字符具有特殊的意義。比如,在字符串中的'/n'表示的是換行,'/b'表示的是回退鍵(Backspace),等等。詳細(xì)的轉(zhuǎn)義字符表可以查看,這個(gè)字符串就是一個(gè)raw字符串。在raw字符串中,所有的轉(zhuǎn)義都將失去作用,所以r'/n'將表示兩個(gè)字符'/'和'n',而不是一個(gè)換行符。
前面我們講到了Python中的轉(zhuǎn)義字符,那轉(zhuǎn)義字符對(duì)正則表達(dá)式有什么影響呢?
我們知道,正則表達(dá)式實(shí)際上就是一個(gè)字符串,和別的字符串的區(qū)別就是它們可以被正則表達(dá)式引擎解析和執(zhí)行。所以,為了使正則表達(dá)式可以正常的工作,我們需要保證傳遞給正則表達(dá)式引擎的正則表達(dá)式字符串的語(yǔ)法是正確的,并且是我們期望的樣子。但是,由于Python中的轉(zhuǎn)義字符的存在,并且,在正則表達(dá)式的元字符中也包含了反斜杠,所以我們需要正確地處理正則表達(dá)式中的反斜杠。
如果我們需要在正則表達(dá)式中使用反斜杠本來(lái)的意思,而不是作為元字符使用,那么我們需要傳遞給正則表達(dá)式引擎的就是一個(gè)'//'表示的字符串。其中第一個(gè)反斜杠用于對(duì)后面的反斜杠進(jìn)行跳脫,使得后面的反斜杠失去元字符的作用。現(xiàn)在,我們需要兩個(gè)反斜杠'//'傳遞給正則表達(dá)式引擎,那么,我們需要用'////'這樣的Python字符串來(lái)表示。為什么呢?因?yàn)椋覀兪窃赑ython中使用正則表達(dá)式,并且正則表達(dá)式是使用Python中的字符串表示的,那么考慮到Python中轉(zhuǎn)義字符的問(wèn)題,我們?nèi)绻枰粋€(gè)反斜杠,那么需要在字符串中這樣表示'//',如果需要兩個(gè),那么就要這樣表示'////'。這樣,我們的Python字符串就會(huì)產(chǎn)生兩個(gè)反斜杠組成的字符串了。
而對(duì)于正則表達(dá)式的一些特殊的元字符,比如'/d',如果用Python的字符串表示,則需要表示成'//d'來(lái)保證傳遞給正則表達(dá)式引擎的是'/d'。
>>> print('//') / >>> print('////') // >>> print('//d') /d如果正則表達(dá)式中包含了很多的反斜杠,這樣會(huì)導(dǎo)致正則表達(dá)式變的復(fù)雜和難以理解,所以,我們一般都用Python的raw字符串來(lái)表示一個(gè)正則表達(dá)式。因?yàn)樵趓aw字符串中,反斜杠將不具有特殊用途,所以r'//'表示'//',r'/d'表示'/d'。
>>> print(r'//') // >>> print(r'/d') /d我們?cè)诰帉懻齽t表達(dá)式的時(shí)候,都應(yīng)該使用Python的raw字符串來(lái)表示。
介紹完了反斜杠的問(wèn)題,下面,我們介紹正則表達(dá)式中的元字符,是它們使得正則表達(dá)式如此靈活和強(qiáng)大的。
注意:這里只是介紹正則表達(dá)式中一些常用的元字符,詳細(xì)的介紹可以參考分隔。如:[abc]可以匹配a、b、c中的任何一個(gè)字符,同樣,也可以用[a-c]來(lái)達(dá)到同樣的效果,[a-c]表示匹配a到c之間的任何一個(gè)字母。如果需要匹配任何一個(gè)小寫字母,則可以這樣寫[a-z]。
在元字符[]中的字符,將會(huì)失去特殊的作用,也就是說(shuō),如果在[]中包含了元字符,則這些元字符將不再具有特使作用,而只是表示字符自身。這可以用來(lái)代替反斜杠來(lái)跳脫元字符:[$]可以和/$達(dá)到相同的效果。
如果需要匹配不再字符類中的字符,則可以對(duì)字符類進(jìn)行取反,使用'^'符號(hào)來(lái)進(jìn)行取反。將'^'符號(hào)放在字符類中的字符集合中的第一個(gè),使得可以匹配不在這個(gè)字符集合中的字符。比如:[^a-z]表示匹配任何不是小寫字母的字符。
>>> p = re.compile(r'[ab]') >>> m = p.search('ababaabaacdefg') >>> m.group() 'a'元字符/w可以匹配字母和數(shù)字。如果正則表達(dá)式是由字節(jié)表示的,則/w相當(dāng)于是字符類[a-zA-Z0-9_]。如果正則表達(dá)式是一個(gè)字符串,則/w將會(huì)匹配所有在Unicode database中標(biāo)記為文字(letters)的字符,Unicode database由模塊unicodedata模塊提供。在編譯正則表達(dá)式的時(shí)候,可以通過(guò)指定 re.ASCII 選項(xiàng)來(lái)限制/w匹配的范圍。
>>> p = re.compile(r'/w') >>> m = p.search('ababaabaacdefg') >>> m.group() 'a'元字符/d將會(huì)匹配數(shù)字,對(duì)于Unicode表示的正則表達(dá)式(str類型),將會(huì)匹配Unicode表示的十進(jìn)制數(shù)字,包括[0-9],以及其他的數(shù)字字符。如果 re.ASCII 選項(xiàng)在編譯的時(shí)候被指定,則只會(huì)匹配[0-9](由于 re.ASCII 選項(xiàng)會(huì)影響整個(gè)正則表達(dá)式,所以在需要匹配0到9組成的數(shù)字的時(shí)候,可以使用[0-9])。對(duì)于8位字節(jié)(bytes類型)表示的正則表達(dá)式,則相當(dāng)于是[0-9]。
>>> p = re.compile(r'/d') >>> m = p.search('123') >>> m.group() '1'元字符/D匹配任何不是Unicode數(shù)字的字符,這個(gè)元字符和/d的相反。如果指定了 re.ASCII 選項(xiàng),則相當(dāng)于是 [^0-9]。
>>> p = re.compile(r'/D') >>> m = p.search('123abc') >>> m.group() 'a' 元字符/s,在Unicode表示(str類型)的正則表達(dá)式中,用于匹配Unicode空白字符,包括[ /t/n/r/f/v],如果 re.ASCII 選項(xiàng)被指定,則只匹配[ /t/b/r/f/v]。對(duì)于8位字節(jié)(bytes)表示的正則表達(dá)式,則和[ /t/n/r/f/v]是等價(jià)的。
>>> p = re.compile(r'/s') >>> m = p.search('hello world') >>> m.group() ' '元字符/S,匹配不是Unicode空白字符的任何字符。和/s相反。如果 re.ASCII 選項(xiàng)被指定,則和 [^ /t/n/r/f/v]等價(jià)。
>>> p = re.compile(r'/S') >>> m = p.search('hello world') >>> m.group() 'h'元字符/W匹配不是Unicode中的Word字符的任何字符。和/w相反。如果指定了 re.ASCII 選項(xiàng),則和 [^a-zA-Z0-9_]等價(jià)。
>>> p = re.compile(r'/W') >>> m = p.search('hello-world') >>> m.group() '-'元字符 .可以匹配除了換行符外的任何一個(gè)字符。但是,如果在編譯的時(shí)候指定了 re.DOTALL 選項(xiàng),則可以匹配任何一個(gè)字符,包括換行符。
>>> p = re.compile(r'.') >>> m = p.search('hello') >>> m.group() 'h'元字符|表示或操作。如果A和B都是正則表達(dá)式,則A|B表示會(huì)匹配A和B中的任何一個(gè)。由于|的優(yōu)先級(jí)具有很低的優(yōu)先級(jí),所以當(dāng)進(jìn)行如下hello|world模式串進(jìn)行匹配的時(shí)候,hello和world之間的任何一個(gè)匹配了,則這個(gè)正則表達(dá)式就匹配成功了,而不是作用于o和w。如果需要在正則表達(dá)式中使用|作為普通的字符,則可以使用反斜杠進(jìn)行轉(zhuǎn)義/|,或者使用字符類[|]。
>>> p = re.compile(r'/d+|/w+') >>> m = p.search('a1b2c3d4') >>> m.group() 'a1b2c3d4'元字符^匹配一行的開頭。除非指定了re.MULTILINE選項(xiàng),否則會(huì)匹配字符串的開頭,如果re.MULTILINE選項(xiàng)被指定,則會(huì)匹配字符串中換行符后面的位置。
如果需要在模式串中去掉元字符的特殊意義,則可以使用反斜杠來(lái)轉(zhuǎn)義/^,或者使用字符類[^]
>>> p = re.compile(r'^hello') >>> p.search('hello world') <_sre.SRE_Match object; span=(0, 5), match='hello'> >>> print(p.search('a word hello')) None元字符$匹配一行的結(jié)尾,一行的結(jié)尾的定義是:一個(gè)字符串的結(jié)尾,當(dāng)指定了re.MULTILNE選項(xiàng)后,會(huì)匹配換行符之前的位置。
如果需要去掉元字符的特殊意義,則可以使用反斜杠進(jìn)行轉(zhuǎn)義/^,或者使用字符類[$]。
>>> p = re.compile(r'd$') >>> p.search('hello world') <_sre.SRE_Match object; span=(10, 11), match='d'> >>> print(p.search('hello')) None >>> p = re.compile(r'/w+d$', re.M) >>> p.search('word/n Word').group() 'word'元字符/A和/Z分別匹配字符串的開頭和結(jié)尾,不會(huì)受到re.MULTILINE選項(xiàng)的影響。當(dāng)沒(méi)有指定re.MULTILINE選項(xiàng)的情況下,^相對(duì)于是/A,而$相當(dāng)于是/Z。(為什么要使用A和Z作為匹配字符串開頭和結(jié)尾的元字符,可能是考慮到A是英文字符的第一個(gè)字母,而Z是英文字符的最后一個(gè)字母的緣故,這樣相對(duì)容易記憶)。
元字符/b匹配單詞的邊界,這是一個(gè)零寬斷言,匹配單詞的邊界(開頭或結(jié)尾)。單詞的定義是:一系列字母數(shù)字組成的序列,所以單詞可以被空白符或者非字母數(shù)字分隔。
>>> p = re.compile(r'/bhello/b') >>> p.search('hello world').group() 'hello' >>> print(p.search('helloworld')) None元字符/B匹配不是單詞邊界的位置,這個(gè)元字符也是一個(gè)零寬斷言,和元字符/b的意思相反。
正則表達(dá)式除了可以通過(guò)元字符匹配任意的字符以外,還具有重復(fù)的能力,可以指定匹配的次數(shù)。
元字符 *匹配重復(fù)前一個(gè)字符或分組0次或多次,如果需要匹配'*'字符,則需要進(jìn)行轉(zhuǎn)義'/*'。由于Python的re模塊中的正則表達(dá)式引擎是采用C編寫的,所以重復(fù)次數(shù)的最大值被int類型的最大值限制,重復(fù)次數(shù)最大為20億次。
Python中正則表達(dá)式引擎的重復(fù)匹配是貪婪的,匹配引擎會(huì)盡可能多的進(jìn)行匹配,直到不能匹配為止,然后匹配引擎會(huì)進(jìn)行回溯,嘗試更小的重復(fù)次數(shù)進(jìn)行匹配,直到匹配上。所以對(duì)于字符串aaaaaab,a*將會(huì)匹配aaaaaa,而不是匹配a。
>>> p = re.compile(r'ca*t') >>> m = p.search('caaat') >>> m.group() 'caaat'元字符+,用于重復(fù)前一個(gè)字符或分組一次或多次。元字符*和+是有區(qū)別的,+要求前一個(gè)字符出現(xiàn)至少一次,而*并不要求前一個(gè)字符一定要出現(xiàn)。所以對(duì)于正則表達(dá)式ca*t,可以匹配ct,但是正則表達(dá)式ca+t將不能匹配ct。
元字符?,用于重復(fù)前一個(gè)字符或分組一次或0次。正則表達(dá)式home-?brew可以匹配home-brew或homebrew。
元字符{m, n},可以匹配前一個(gè)字符或分組m ~ n次。正則表達(dá)式a/{1,3}b將會(huì)匹配a/b和a//b和a///b。如果省略了m,則表示匹配0 ~ n次,如果省略了n,則表示至少匹配m次。因此,{0,}和*是等價(jià)的,{0,1}和?是等價(jià)的,{1,}和+是等價(jià)的。
現(xiàn)在,我們已經(jīng)對(duì)正則表達(dá)式有了一些了解,也知道了正則表達(dá)式中元字符的作用。下面,我們開始結(jié)合Python的re模塊來(lái)學(xué)習(xí)使用這些正則表達(dá)式。
Python的re模塊提供了一套接口來(lái)使用正則表達(dá)式引擎,通過(guò)re模塊提供的接口,可以將正則表達(dá)式編程成正則表達(dá)式對(duì)象,然后進(jìn)行需要的匹配操作。
正則表達(dá)式可以被編譯成模式對(duì)象,然后調(diào)用模式對(duì)象的方法來(lái)進(jìn)行字符串匹配操作,比如搜索、替換或者分割。
通過(guò)re模塊的compile()函數(shù)可以將一個(gè)正則表達(dá)式編譯成一個(gè)模式對(duì)象
re.compile(pattern, flags=0) >>> import re >>> p = re.compile(r'a*') >>> p re.compile('a*')傳遞給re.compile()函數(shù)一個(gè)可選的flags參數(shù),可以控制編譯后的對(duì)象在匹配的時(shí)候的行為。
flags 參數(shù)的值可以是以下的值:
re.A | re.ASCII
: 對(duì)/w、/W、/b、/B、/d、/D、/s和/S產(chǎn)生影響,編譯后的模式對(duì)象在進(jìn)行匹配的時(shí)候,只會(huì)匹配ASCII字符,而不是Unicode字符。
這個(gè)選項(xiàng)只對(duì)Unicode模式串有效,對(duì)字節(jié)模式串無(wú)效。 re.I | re.IGNORECASE
: 在匹配的時(shí)候忽略大小寫,在字符類和字符字面值進(jìn)行匹配的時(shí)候會(huì)忽略大小寫。進(jìn)行大小寫轉(zhuǎn)換的時(shí)候,不會(huì)考慮當(dāng)前的locale信息,除非指定了re.LOCALE選項(xiàng)。
>>> p = re.compile(r'[a-z]+', re.I) >>> m = p.search('abcdABCD') >>> m.group() abcdABCDre.M | re.MULTILINE
: 默認(rèn),元字符^會(huì)匹配字符串的開始處,元字符$會(huì)匹配字符串的結(jié)束位置和字符串后面緊跟的換行符之前(如果存在這個(gè)換行符)。如果指定了這個(gè)選項(xiàng),則^將會(huì)匹配字符串的開頭和每一行的開始處,緊跟在每一個(gè)換行符后面的位置。類似的,$會(huì)匹配字符串的最后和每一行的最后,在接下來(lái)的換行符的前面的位置。
>>> p = re.compile(r'(^hello$)/s(^hello$)/s(^hello$)/s') >>> m = p.search('hello/nhello/nhello/n') >>> print(m) None >>> p = re.compile(r'(^hello$)/s(^hello$)/s(^hello$)/s', re.M) >>> m = p.search('/nhello/nhello/nhello/n') >>> m.groups() ('hello', 'hello', 'hello')re.S | re.DOTALL
: 使得.元字符可以匹配任何字符,包括換行符。
re.X | re.VERBOSE
: 這個(gè)選項(xiàng)允許編寫可讀性更強(qiáng)的正則表達(dá)式代碼,并進(jìn)行自由的格式化操作。當(dāng)這個(gè)選項(xiàng)被指定以后,在正則表達(dá)式之間的空格符會(huì)被忽略,除非這個(gè)空格符是在一個(gè)字符類中[ ],或者在空格前使用一個(gè)反斜杠/。這個(gè)選項(xiàng)允許對(duì)正則表達(dá)式進(jìn)行縮進(jìn),使得正則表達(dá)式的代碼更加格式化,更加清晰。并且可以在正則表達(dá)式的代碼中使用注釋,這些注釋會(huì)被正則表達(dá)式引擎在處理的時(shí)候忽略。注釋以'#'字符開頭。所以如果需要在正則表達(dá)式中使用'#'符號(hào),需要在前面添加反斜杠'/#'或者將它放在[]中,[#]。
charref = re.compile(r""" &[#] # Start of a numeric entity reference ( 0[0-7]+ # Octal form | [0-9]+ # Decimal form | x[0-9a-fA-F]+ # Hexadecimal form ) ; # Trailing semicolon """, re.VERBOSE)如果沒(méi)有指定re.**VERBOSE**選項(xiàng),則相當(dāng)于: charref = re.compile("&#(0[0-7]+" "|[0-9]+" "|x[0-9a-fA-F]+);")一旦我們通過(guò)re.compile()編譯后產(chǎn)生了一個(gè)正則表達(dá)式對(duì)象,我們就可以通過(guò)這個(gè)正則表達(dá)式對(duì)象進(jìn)行匹配操作了。re模塊的正則表達(dá)式對(duì)象包含了一些方法,可以進(jìn)行需要的匹配操作。
| 方法 | 描述 |
|---|---|
| match() | 從字符串開頭位置開始匹配 |
| search() | 對(duì)字符串的任意位置進(jìn)行匹配 |
| findall() | 返回字符串中所有匹配的子串組成的列表 |
| finditer() | 返回一個(gè)包含了所有的匹配對(duì)象的迭代器 |
如果沒(méi)有匹配到,則match()和search()方法返回None,如果匹配成功,則返回一個(gè)匹配對(duì)象。返回的匹配對(duì)象包含了匹配信息:包括匹配的子串的開始位置和結(jié)束位置等信息。
>>> p = re.compile(r'[a-z]+') >>> print(p.match('hello123')) <_sre.SRE_Match object; span=(0, 5), match='hello'> >>> print(p.match('123hello')) None >>> print(p.search('123hello')) <_sre.SRE_Match object; span=(3, 8), match='hello'> >>> p = re.compile(r'/d+') >>> p.findall('a number A is 12, and a number B is 8, A + B = 20') ['12', '8', '20'] >>> i = p.finditer('a number A is 12, and a number B is 8, A + B = 20') >>> for item in i: print(item.group()) 12 8 20除了使用正則表達(dá)式對(duì)象中的方法,re模塊也提供了一些模塊級(jí)別的同名函數(shù)來(lái)進(jìn)行匹配操作。包括:match(),search(),findall()和sub()等函數(shù)。這些函數(shù)接受和正則表達(dá)式對(duì)象中的方法類似的參數(shù),除了第一個(gè)參數(shù)是一個(gè)正則表達(dá)式字符串以外,后面的參數(shù)和正則表達(dá)式對(duì)象中的方法接受的參數(shù)是一致的。并且這些函數(shù)的返回值也是相同的。
>>> re.search(r'/d+', 'a number A is 12') <_sre.SRE_Match object; span=(14, 16), match='12'> >>> re.findall(r'/d+', 'a number A is 12, and a number B is 8, A + B = 20') ['12', '8', '20']實(shí)際上,這些函數(shù)在底層會(huì)對(duì)正則表達(dá)式字符串進(jìn)行編譯,產(chǎn)生一個(gè)正則表達(dá)式對(duì)象,然后調(diào)用正則表達(dá)式中同名的方法來(lái)實(shí)現(xiàn)。并且,這些函數(shù)會(huì)將正則表達(dá)式對(duì)象緩存起來(lái),所以下次再次使用相同的正則表達(dá)式的時(shí)候,就可以不用再次對(duì)這個(gè)正則表達(dá)式進(jìn)行編譯了。
對(duì)于使用模塊級(jí)別的函數(shù)還是使用正則表達(dá)式對(duì)象中的方法來(lái)進(jìn)行匹配,需要依據(jù)不同的使用場(chǎng)景來(lái)權(quán)衡。如果是在循環(huán)中,則使用編譯好的正則表達(dá)式對(duì)象會(huì)相對(duì)高效,而在循環(huán)外,由于緩存的存在,這兩種方式區(qū)別不大。
我們得到匹配對(duì)象以后,就可以通過(guò)匹配對(duì)象中的方法對(duì)匹配的信息進(jìn)行進(jìn)一步的處理了。
匹配對(duì)象中重要的方法如下:
| 方法 | 描述 |
|---|---|
| group() | 返回正則表達(dá)式匹配到的字符串 |
| start() | 返回匹配的起始位置 |
| end() | 返回匹配的結(jié)束位置 |
| span() | 返回一個(gè)包含匹配的起始位置和結(jié)束位置的元組(start, end) |
>>> p = re.compile(r'[a-z]+') >>> m = p.search('123hello') >>> m <_sre.SRE_Match object; span=(3, 8), match='hello'> >>> m.group() 'hello' >>> m.start() 3 >>> m.end() 8 >>> m.span() (3, 8)雖然正則表達(dá)式很強(qiáng)大,可以靈活地處理很多字符串處理得工作。但是,由于正則表達(dá)式語(yǔ)言相對(duì)嚴(yán)格和小巧,所以一些字符串處理工作,正則表達(dá)式并不能處理的很好。
在一些情況下,并不適合使用正則表達(dá)式,相反,使用Python的字符串中的方法,可能更加合適。比如,如果你需要對(duì)一個(gè)字符串進(jìn)行匹配,而匹配的模式串是一個(gè)固定的字符串的話,那么,使用Python中的字符串中的一些方法,如replace()方法,會(huì)比使用正則表達(dá)式來(lái)的更加高效和簡(jiǎn)單。
因此,在我們使用Python的re模塊中的正則表達(dá)式來(lái)進(jìn)行字符串的處理工作之前,我們不妨考慮下,是否可以使用字符串中簡(jiǎn)單高效的方法來(lái)解決。
這篇文章沒(méi)有提到正則表達(dá)式中的分組(group),在re模塊中也支持分組,并且添加了Python的一些特性,后續(xù)再來(lái)介紹下re模塊中的分組的使用,以及一些別的特性。
https://docs.python.org/3/howto/regex.html
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注