一文讀懂正則表達(dá)式的基本用法

什么是正則表達(dá)式童叠?

正則表達(dá)式是對(duì)字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合齿坷,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來(lái)表達(dá)對(duì)字符串的一種過(guò)濾邏輯数焊。

正則表達(dá)式不是Python獨(dú)有的永淌,目前主流的開(kāi)發(fā)語(yǔ)言都支持正則表達(dá)式,在Python中是使用re模塊來(lái)實(shí)現(xiàn)正則表達(dá)式佩耳。

正則表達(dá)式常用符號(hào)

符號(hào) 含義
* 匹配0個(gè)或多個(gè)表達(dá)式
+ 匹配1個(gè)或多個(gè)表達(dá)式
^ 匹配字符串的開(kāi)頭
$ 匹配字符串的結(jié)尾
. 匹配任意單個(gè)字符遂蛀,換行符除外
\ 轉(zhuǎn)義字符,把有特殊含義的字符轉(zhuǎn)換為字面形式
? 匹配0或多個(gè)表達(dá)式干厚,非貪婪模式
a|b 匹配a或b
() 匹配括號(hào)內(nèi)的表達(dá)式李滴, 也表示一個(gè)組
[] 匹配其中的任意一個(gè)字符
[^] 匹配任意一個(gè)不在中括號(hào)里的字符
\n 匹配換行符
\t 匹配制表符
\w 匹配任意字母數(shù)字及下劃線
\s 匹配任意空白字符
\d 匹配任意數(shù)字

match函數(shù)

re.match會(huì)嘗試從字符串的起始位置匹配一個(gè)字符串表達(dá)式,如果匹配成功就返回匹配結(jié)果蛮瞄,如果匹配失敗就返回None.

比如這里有一個(gè)字符串:

    content = 'open the command palette 123456 Hello world!'

我想要匹配出其中的數(shù)字所坯,可以這樣寫(xiě):

import re

content = 'open the command palette 123456 Hello world!'

# 在match方法中,第一個(gè)參數(shù)為正則表達(dá)式挂捅,第二個(gè)參數(shù)為待匹配的字符串
result = re.match('^open.*?(\d+).*?world!$', content)
print(result)
print(result.group(1)) 
<_sre.SRE_Match object; span=(0, 44), match='open the command palette 123456 Hello world!'>
123456

這里^open指定了字符串的開(kāi)頭包竹,.*?表示以非貪婪模式匹配0或多個(gè)字符,(\d+)表示我們想要提取的是1到多個(gè)數(shù)字,需要提取的內(nèi)容一定要放在小括號(hào)里周瞎,后面接著.*?表示以非貪婪模式匹配0或多個(gè)字符苗缩,最后的world!$指定了字符串的結(jié)尾。

這里group(1)表示提取第一個(gè)小括號(hào)里的內(nèi)容声诸,如果有多個(gè)小括號(hào)酱讶,可分別使用group(2),group(3)來(lái)提取。

貪婪匹配與非貪婪匹配的區(qū)別

在上面的例子中彼乌,我們使用了.*?表示以非貪婪模式匹配0或多個(gè)字符泻肯,這里如果將?去掉,就變成了貪婪模式慰照,它們之間的具體區(qū)別是什么呢灶挟?看下面這個(gè)例子:

import re

content = 'open the command palette 123456 Hello world!'

# 這里將(\d+)前面的?去掉毒租,其他不變稚铣。
result = re.match('^open.*(\d+).*?world!$', content)
print(result)
print(result.group(1)) 
<_sre.SRE_Match object; span=(0, 44), match='open the command palette 123456 Hello world!'>
6

如上,匹配結(jié)果變成了一個(gè)6,而前面的12345不見(jiàn)了墅垮,這是因?yàn)?code>.*是以貪婪模式匹配惕医,它會(huì)匹配盡可能多的字符,緊接著的\d+也就只匹配到了一個(gè)數(shù)字6

關(guān)于包含換行符的匹配

在實(shí)際的正則匹配過(guò)程中算色,我們需要匹配的字符串常是很多行抬伺,這其中就必定包含了換行符,這個(gè)時(shí)候就要使用修飾符re.S來(lái)匹配包含了換行符的字符串灾梦。如下例:

import re

# 有換行的字符串要用三引號(hào)''''''引起來(lái)
content = '''open the command palette 
            123456 Hello world!'''

# 這里加入修飾符re.S
result = re.match('^open.*?(\d+).*?world!$', content, re.S) 
print(result)
print(result.group(1)) 
<_sre.SRE_Match object; span=(0, 57), match='open the command palette \n            123456 Hel>
123456

在網(wǎng)頁(yè)匹配中峡钓,常用的修飾符有兩種:

  • re.S :匹配包含換行符在內(nèi)的所有字符
  • re.I :使匹配對(duì)大小寫(xiě)不敏感

關(guān)于轉(zhuǎn)義字符的匹配

上面我們羅列的一堆正則表達(dá)式的常用字符,這些字符可以稱(chēng)為特殊字符若河,如果待匹配的字符串中本身就包含了這些特殊字符椒楣,如果不加處理,就會(huì)對(duì)我們的正則匹配造成干擾牡肉,這個(gè)時(shí)候就需要用反斜杠\來(lái)進(jìn)行轉(zhuǎn)義:

import re

content = 'price is $10.00'
result = re.match('^price.*?\$10\.00$', content)
print(result)
<_sre.SRE_Match object; span=(0, 15), match='price is $10.00'>

這里使用\$\.對(duì)字符$.分別進(jìn)行轉(zhuǎn)義

search函數(shù)

上面講到的match函數(shù)是從字符串的開(kāi)頭進(jìn)行逐個(gè)匹配,如果開(kāi)頭不匹配淆九,則匹配失敗统锤,它的執(zhí)行效率有點(diǎn)類(lèi)似與單鏈表的查詢操作,得從頭開(kāi)始挨著一個(gè)一個(gè)找炭庙,而search函數(shù)是首先是掃描整個(gè)字符串饲窿,然后返回第一個(gè)成功匹配的結(jié)果。

在很大一堆的字符串中焕蹄,如果我們只需要其中的一小段字符串逾雄,就可以使用search函數(shù)進(jìn)行匹配:

import re 

content = 'open the command palette 123456 Hello world!'
result = re.search('command.*?(\d+).*?world!', content)
print(result)
print(result.group(1))
<_sre.SRE_Match object; span=(9, 44), match='command palette 123456 Hello world!'>
123456

下面來(lái)看個(gè)例子,這是我在豆瓣讀書(shū)的網(wǎng)頁(yè)上復(fù)制的一段HTML代碼:

HTML = """<div class="pl2">


              <a  onclick="&quot;moreurl(this,{i:'0'})&quot;" title="追風(fēng)箏的人">
                追風(fēng)箏的人

                
              </a>



                &nbsp; <img src="https://img3.doubanio.com/pics/read.gif" alt="可試讀" title="可試讀">

              
                <br>
                <span style="font-size:12px;">The Kite Runner</span>
</div>
<p class="pl">[美] 卡勒德·胡賽尼 / 李繼宏 / 上海人民出版社 / 2006-5 / 29.00元</p>
<div class="star clearfix">
                  <span class="allstar45"></span>
                  <span class="rating_nums">8.9</span>

                <span class="pl">(
                    315272人評(píng)價(jià)
                )</span>
              </div>"""

這里我想用正則表達(dá)式匹配這本《追風(fēng)箏的人》圖書(shū)的書(shū)名,作者鸦泳,評(píng)分和評(píng)價(jià)人數(shù)银锻,我們可以這樣匹配:

import re 

result = re.search('<a.*?>(.*?)</a>.*?<p.*?>(.*?)</p>.*?rating_nums.*?>(.*?)</span>.*?>\((.*?)\)</span>', HTML, re.S)
print(result)
print(result.group(1))
print(result.group(2))
print(result.group(3))
print(result.group(4))
<_sre.SRE_Match object; span=(34, 703), match='<a href="https://book.douban.com/subject/1770782/>

                追風(fēng)箏的人

                
              
[美] 卡勒德·胡賽尼 / 李繼宏 / 上海人民出版社 / 2006-5 / 29.00元
8.9

                    315272人評(píng)價(jià)

我解釋一下上面這句正則表達(dá)式,<a.*?>(.*?)</a>用來(lái)匹配書(shū)名做鹰,<p.*?>(.*?)</p>用來(lái)匹配作者信息击纬, rating_nums.*?>(.*?)</span>用來(lái)匹配評(píng)分,>\((.*?)\)</span>用來(lái)匹配評(píng)分人數(shù)钾麸,這里要將每一個(gè)需要提取的信息放在小括號(hào)里更振,以待下一步的輸出,然后不同有用信息的正則表達(dá)式之間用.*?來(lái)連接饭尝,最后指定修飾符re.S進(jìn)行換行匹配

然后調(diào)用result.group(1)來(lái)輸出第一個(gè)小括號(hào)里的內(nèi)容肯腕,調(diào)用result.group(2)來(lái)輸出第二個(gè)小括號(hào)里的內(nèi)容,以此類(lèi)推钥平,但是從輸出結(jié)果我們可以看到有多余的空白行和我不想要的信息实撒,比如出版社和圖書(shū)價(jià)格,這里將輸出稍微整理一下:

import re 

result = re.search('<a.*?>(.*?)</a>.*?<p.*?>(.*?)</p>.*?rating_nums.*?>(.*?)</span>.*?>\((.*?)\)</span>', HTML, re.S)
print(result)
print(result.group(1).strip())
print(result.group(2).strip()[:12])
print(result.group(3).strip())
print(result.group(4).strip())
<_sre.SRE_Match object; span=(34, 703), match='<a href="https://book.douban.com/subject/1770782/>
追風(fēng)箏的人
[美] 卡勒德·胡賽尼 
8.9
315272人評(píng)價(jià)

如上帖池,得到了我想要的信息奈惑。

希望這個(gè)示例對(duì)你有所啟發(fā)。

findall()函數(shù)

在整個(gè)網(wǎng)頁(yè)的正則匹配中睡汹,我們想要的信息往往處在一組同名的標(biāo)簽下類(lèi)似的位置肴甸,只是屬性值有所不同,想要提取這樣的信息囚巴,就要使用findall()函數(shù)原在,該方法會(huì)搜索整個(gè)字符串,然后返回匹配正則表達(dá)式的所有內(nèi)容彤叉。相當(dāng)于search()函數(shù)的拓展庶柿。

具體示例省略

compile()函數(shù)

這個(gè)方法可以將正則字符串編譯成正則表達(dá)式對(duì)象,以便在后面的匹配中方便調(diào)用秽浇。例如:

import re 

pattern = re.compile('<a.*?>(.*?)</a>.*?<p.*?>(.*?)</p>.*?rating_nums.*?>(.*?)</span>.*?>\((.*?)\)</span>', re.S)
result = re.search(pattern, HTML)
print(result)
print(result.group(1).strip())
print(result.group(2).strip()[:12])
print(result.group(3).strip())
print(result.group(4).strip())
<_sre.SRE_Match object; span=(34, 703), match='<a href="https://book.douban.com/subject/1770782/>
追風(fēng)箏的人
[美] 卡勒德·胡賽尼 
8.9
315272人評(píng)價(jià)

正則表達(dá)式的基本用法大致就是這些浮庐,下節(jié)我們嘗試用正則表達(dá)式寫(xiě)一個(gè)小爬蟲(chóng)。

每天學(xué)習(xí)一點(diǎn)點(diǎn)柬焕,每天進(jìn)步一點(diǎn)點(diǎn)审残。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市斑举,隨后出現(xiàn)的幾起案子搅轿,更是在濱河造成了極大的恐慌,老刑警劉巖富玷,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件璧坟,死亡現(xiàn)場(chǎng)離奇詭異既穆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)雀鹃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)幻工,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人褐澎,你說(shuō)我怎么就攤上這事会钝。” “怎么了工三?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵迁酸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我俭正,道長(zhǎng)奸鬓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任掸读,我火速辦了婚禮串远,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘儿惫。我一直安慰自己澡罚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布肾请。 她就那樣靜靜地躺著留搔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铛铁。 梳的紋絲不亂的頭發(fā)上隔显,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音饵逐,去河邊找鬼括眠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛倍权,可吹牛的內(nèi)容都是我干的掷豺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼薄声,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼当船!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起奸柬,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎婴程,沒(méi)想到半個(gè)月后廓奕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年桌粉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒸绩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铃肯,死狀恐怖患亿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情押逼,我是刑警寧澤步藕,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站挑格,受9級(jí)特大地震影響咙冗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜漂彤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一雾消、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挫望,春花似錦立润、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至拷肌,卻和暖如春到旦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巨缘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工添忘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人若锁。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓搁骑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親又固。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仲器,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容