2.9.2.1Python-解析庫_re(正則表達(dá)式)

總目錄:http://www.reibang.com/p/e406a9bc93a9

Python-爬蟲 - 子目錄:http://www.reibang.com/p/23cf57674bf1

文檔:https://docs.python.org/3/library/re.html

正則表達(dá)式語言相對小型和受限(功能有限),因此并非所有字符串處理都能用正則表達(dá)式完成。

當(dāng)然也有些任務(wù)可以用正則表達(dá)式完成沛硅,不過最終表達(dá)式會(huì)變得異常復(fù)雜眼刃。碰到這些情形時(shí),編寫Python 代碼進(jìn)行處理可能反而更好摇肌;盡管 Python 代碼比一個(gè)精巧的正則表達(dá)式要慢些擂红,但它更易理解。


常用方法

re.compile: 編譯一個(gè)正則表達(dá)式模式(pattern)

re.match: 從頭開始匹配, 使用group()方法可以獲取第一個(gè)匹配值

re.search: 用包含方式匹配围小,使用group()方法可以獲取第一個(gè)匹配值

re.findall: 用包含方式匹配昵骤,把所有匹配到的字符放到以列表中的元素返回多個(gè)匹配值

re.sub: 匹配字符并替換

re.split: 以匹配到的字符當(dāng)做列表分隔符,返回列表



基本模式

簡單字符

沒有特殊意義的字符都是簡單字符肯适,簡單字符就代表自身变秦,絕大部分字符都是簡單字符,舉個(gè)例子

/abc/ //匹配 abc

/123/ //匹配 123

/-_-/ //匹配 -_-


轉(zhuǎn)義字符

第一種框舔,是為了匹配不方便顯示的特殊字符蹦玫,比如換行,tab符號等

第二種雨饺,正則中預(yù)先定義了一些代表特殊意義的字符钳垮,比如\w等

第三種,在正則中某些字符有特殊含義(比如下面說到的)额港,轉(zhuǎn)義字符可以讓其顯示自身的含義


字符集合

有時(shí)我們需要匹配一類字符饺窿,字符集可以實(shí)現(xiàn)這個(gè)功能,字符集的語法用[]分隔移斩,下面的代碼能夠匹配a或b或c

[abc]

如果要表示字符很多肚医,可以使用-表示一個(gè)范圍內(nèi)的字符,下面兩個(gè)功能相同

[0123456789]

[0-9]

在前面添加^向瓷,可表示非的意思肠套,下面的代碼能夠匹配abc之外的任意字符

[^abc]

其實(shí)正則還內(nèi)置了一些字符集,在上面的轉(zhuǎn)義字符有提到猖任,下面給出內(nèi)置字符集對應(yīng)的自定義字符集

.匹配除了換行符(\n)以外的任意一個(gè)字符 = [^\n]

\w = [0-9a-Z_]

\W = [^0-9a-Z_]

\s = [ \t\n\v]

\S = [^ \t\n\v]

\d = [0-9]

\D = [^0-9]

量詞

如果我們有三個(gè)蘋果你稚,我們可以說自己有個(gè)3個(gè)蘋果,也可以說有一個(gè)蘋果朱躺,一個(gè)蘋果刁赖,一個(gè)蘋果,每種語言都有量詞的概念

如果需要匹配多次某個(gè)字符长搀,正則也提供了量詞的功能宇弛,正則中的量詞有多個(gè),如?源请、+枪芒、*彻况、{n}、{m,n}舅踪、{m,}

{n}匹配n次纽甘,比如a{2},匹配aa

{m, n}匹配m-n次硫朦,優(yōu)先匹配n次贷腕,比如a{1,3},可以匹配aaa咬展、aa、a

{m,}匹配m-∞次瞒斩,優(yōu)先匹配∞次破婆,比如a{1,},可以匹配aaaa...

?匹配0次或1次胸囱,優(yōu)先匹配1次祷舀,相當(dāng)于{0,1}

+匹配1-n次,優(yōu)先匹配n次烹笔,相當(dāng)于{1,}

*匹配0-n次裳扯,優(yōu)先匹配n次,相當(dāng)于{0,}

正則默認(rèn)和人心一樣是貪婪的谤职,也就是常說的貪婪模式饰豺,凡是表示范圍的量詞,都優(yōu)先匹配上限而不是下限

a{1, 3} //匹配字符串'aaa'的話允蜈,會(huì)匹配aaa而不是a

有時(shí)候這不是我們想要的結(jié)果冤吨,可以在量詞后面加上?,就可以開啟非貪婪模式

a{1, 3}? //匹配字符串'aaa'的話饶套,會(huì)匹配a而不是aaa

字符邊界

有時(shí)我們會(huì)有邊界的匹配要求漩蟆,比如已xxx開頭,已xxx結(jié)尾

^在[]外表示匹配開頭的意思

^abc //可以匹配abc妓蛮,但是不能匹配aabc

$表示匹配結(jié)尾的意思

abc$ //可以匹配abc怠李,但是不能匹配abcc

上面提到的\b表示單詞的邊界

abc\b //可以匹配 abc,但是不能匹配 abcc

選擇表達(dá)式

有時(shí)我們想匹配x或者y蛤克,如果x和y是單個(gè)字符捺癞,可以使用字符集,[abc]可以匹配a或b或c咖耘,如果x和y是多個(gè)字符翘簇,字符集就無能為力了,此時(shí)就要用到分組

正則中用|來表示分組儿倒,a|b表示匹配a或者b的意思

123|456|789 //匹配 123 或 456 或 789

分組和引用

分組是正則中非常強(qiáng)大的一個(gè)功能版保,可以讓上面提到的量詞作用于一組字符呜笑,而非單個(gè)字符,分組的語法是圓括號包裹(xxx)

(abc){2}? ? ?//匹配abcabc

分組不能放在[]中彻犁,分組中還可以使用選擇表達(dá)式

(123|456){2}? ? ?//匹配 123123叫胁、456456、123456汞幢、456123

和分組相關(guān)的概念還有一個(gè)捕獲分組和非捕獲分組驼鹅,分組默認(rèn)都是捕獲的,在分組的(后面添加?:可以讓分組變?yōu)榉遣东@分組森篷,非捕獲分組可以提高性能和簡化邏輯

'123'.match(/(?123)/) //返回 ['123']

'123'.match(/(123)/)? //返回 ['123', '123']

和分組相關(guān)的另一個(gè)概念是引用输钩,比如在匹配html標(biāo)簽時(shí),通常希望后面的xxx能夠和前面保持一致

引用的語法是\數(shù)字仲智,數(shù)字代表引用前面第幾個(gè)捕獲分組买乃,注意非捕獲分組不能被引用

<([a-z]+)><\/\1> //可以匹配 ``或 ``等

預(yù)搜索

如果你想匹配xxx前不能是yyy,或者xxx后不能是yyy钓辆,那就要用到預(yù)搜索

js只支持先行預(yù)搜索剪验,也就是xxx前面必須是yyy,或者xxx前面不能是yyy

(?=1)2 //可以匹配12前联,不能匹配22

(?!1)2 //可有匹配22功戚,不能匹配12

修飾符

默認(rèn)正則是區(qū)分大小寫,這可能并不是我們想要的似嗤,正則提供了修飾符的功能啸臀,修復(fù)的語法如下

/xxx/gi //最后面的g和i就是兩個(gè)修飾符

g正則遇到第一個(gè)匹配的字符就會(huì)結(jié)束,加上全局修復(fù)符双谆,可以讓其匹配到結(jié)束

i正則默認(rèn)是區(qū)分大小寫的壳咕,i可以忽略大小寫

m正則默認(rèn)遇到換行符就結(jié)束了,不能匹配多行文本顽馋,m可以讓其匹配多行文本



主要方法

re.compile方法

compile 函數(shù)用于編譯正則表達(dá)式谓厘,生成一個(gè)正則表達(dá)式( Pattern )對象,供 match() 和 search() 這兩個(gè)函數(shù)使用寸谜。

語法:

re.compile(pattern[, flags])


pattern :一個(gè)字符串形式的正則表達(dá)式

flags :可選竟稳,表示匹配模式,比如忽略大小寫熊痴,多行模式等他爸,具體參數(shù)為:

re.I忽略大小寫

re.L表示特殊字符集 \w, \W, \b, \B, \s, \S依賴于當(dāng)前環(huán)境

re.M多行模式

re.S即為 .并且包括換行符在內(nèi)的任意字符(.不包括換行符)

re.U表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S依賴于 Unicode字符屬性數(shù)據(jù)庫

re.X為了增加可讀性,忽略空格和 # 后面的注釋

上述flags re.I和re.M是非常常用的果善。如果要同時(shí)使用兩個(gè)flags诊笤,可以使用re.I | re.M。


例子:
我們編寫了一個(gè)電子郵箱的正則表達(dá)式巾陕,并用它來驗(yàn)證用戶輸入的郵箱是否有效讨跟。

email_pattern = re.compile(r'^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+){0,4}@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+){0,4}$')

print(re.match(email_pattern, 'django@pyghon.org'))

print(re.match(email_pattern, '1009070053@qq.com'))

<_sre.SRE_Match object; span=(0, 17), match='django@pyghon.org'><_sre.SRE_Match object; span=(0, 17), match='1009070053@qq.com'>


re.match和re.search方法

re.match和re.search方法類似纪他,唯一不同的是re.match從頭匹配,re.search可以從字符串中任一位置匹配晾匠。如果有匹配對象match返回茶袒,可以使用match.group()提取匹配字符串。

語法:

re.match(pattern, string)

re.search(pattern, string)

pattern :一個(gè)字符串形式的正則表達(dá)式

string :要匹配的字符串


例子:
編寫了一個(gè)年份的正則表達(dá)式

import re


year_pattern = re.compile(r'\d{4}')# 四位整數(shù)凉馆,匹配年份

string1 ='我愛1998和1999年'

match1 = re.match(year_pattern, string1)

print(match1)

match2 = re.search(year_pattern, string1)

print(match2)

print(match2.group())

None?

<_sre.SRE_Match object; span=(2, 6), match='1998'>?

1998?

你可以看到re.match沒有任何匹配薪寓,而re.search也只是匹配到1998年,而沒有匹配到1999年澜共。這是為什么呢向叉?

re.match是從頭匹配的,從頭沒有符合正則表達(dá)式咳胃,就返回None植康。

re.search方法雖然可以從字符串任何位置開始搜索匹配,但一旦找到第一個(gè)匹配對象展懈,其就停止工作了。


如何從"Elephants are bigger than rats"里提取Elephants和bigger兩個(gè)單詞


import re

string3 ="Elephants are bigger than rats";

match3 = re.search(r'(.*) are (.*?) .*', string3, re.M|re.I)

print(match3.group())

print(match3.group(1))

print(match3.group(2))

Elephants are bigger than rats

Elephants?

bigger?

match.group的編號是從1開始的供璧,而不是像列表一樣從0開始存崖。


有的符號如", ', )本身就有特殊的含義,我們在正則表達(dá)中使用時(shí)必需先對它們進(jìn)行轉(zhuǎn)義睡毒,方法就是在其符號前件反斜杠\来惧。

下例展示了我們?nèi)绾螐摹翱偣矘菍?共7層)"提取共7層三個(gè)字,我們需要給括號轉(zhuǎn)義演顾。

import re

string4 ="總共樓層(共7層)"

pattern5 = re.compile(r'\(.*\)')

match5 = re.search(pattern5, string4)

print(match5.group())

pattern6 = re.compile(r'\((.*)\)')

match6 = re.search(pattern6, string4)

print(match6.group())

print(match6.group(1))

(共7層)

(共7層)?

共7層??

我們pattern5和pattern6中都對外面雙括號都加了反斜杠\供搀,表明這是括號符號本身。在pattern6中我們還使用了一對沒加反斜杠的括號钠至,表明這是一個(gè)match group葛虐。


如果我們有”總共樓層(共7層)干擾)樓層"這樣的字符串,加了個(gè)干擾問號棉钧,那我們該如何匹配(共7層)呢屿脐?

import re

string10 ="總共樓層(共7層)干擾)問號"

pattern10 = re.compile(r'\(.*\)')# 默認(rèn)貪婪模式

pattern11 = re.compile(r'\(.*?\)')# 加問號?變非貪婪模式

print(re.search(pattern10, string10).group())

print(re.search(pattern11, string10).group())

(共7層)干擾)

(共7層)

Python里正則匹配默認(rèn)是貪婪的,總是嘗試匹配盡可能多的字符宪卿。

非貪婪的則相反的诵,總是嘗試匹配盡可能少的字符。如果要使用非貪婪模式佑钾,我們需要在., *, ?號后面再加個(gè)問號?即可西疤。


re.findall方法

試圖從一個(gè)字符串中提取所有符合正則表達(dá)式的字符串列表時(shí)需要使用re.findall方法。

findall方法使用方法有兩種休溶,一種是pattern.findall(string) 代赁,另一種是re.findall(pattern, string)扰她。

re.findall方法經(jīng)常用于從爬蟲爬來的文本中提取有用信息。


語法:

pattern.findall(string)

re.findall(pattern, string)

pattern : 一個(gè)字符串形式的正則表達(dá)式

string : 要匹配的字符串


例子:
提取年份列表

import re

year_pattern = re.compile(r'\d{4}')# 四位整數(shù)管跺,匹配年份

string1 ='我愛1998和1999年'

print(year_pattern.findall(string1))

['1998', '1999']


提取百度首頁帶有鏈接的關(guān)鍵詞

import re

import requests


response = requests.get('https://www.baidu.com')

response.encoding="utf-8"

urls = re.findall(r'<a.*>(.*)</a>', response.text,)# 獲取帶鏈接的關(guān)鍵詞

for urlin urls:

print(url)

登錄

意見反饋


re.sub方法

該方法經(jīng)常用于去除空格义黎,無關(guān)字符或隱藏敏感字符。

語法:

re.sub(pattern, new_string, current_string)

pattern :一個(gè)字符串形式的正則表達(dá)式

new_string :要替換的字符串

current_string :要匹配的字符串


實(shí)例:
如何把年份替換為****

import re

year_pattern = re.compile(r'\d{4}')# 四位整數(shù)豁跑,匹配年份

string1 ='我愛1998和1999年'

replaced_str = re.sub(year_pattern, '****', string1)

print(replaced_str)

我愛****和****年


re.split方法

split方法用于分割字符串廉涕,但是并不完美

語法:

re.split(pattern, string)

pattern :一個(gè)字符串形式的正則表達(dá)式

string :要匹配的字符串


例子:
分割后的字符串成列表

import re

string1 ="1cat2dogs3cats4"

list1 = re.split(r'\d+', string1)

print(list1)

['', 'cat', 'dogs', 'cats', '']

列表首尾都多了空格,需要手動(dòng)去除艇拍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狐蜕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卸夕,更是在濱河造成了極大的恐慌层释,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件快集,死亡現(xiàn)場離奇詭異贡羔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)个初,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門乖寒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人院溺,你說我怎么就攤上這事楣嘁。” “怎么了珍逸?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵逐虚,是天一觀的道長。 經(jīng)常有香客問我谆膳,道長叭爱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任摹量,我火速辦了婚禮涤伐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缨称。我一直安慰自己凝果,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布睦尽。 她就那樣靜靜地躺著器净,像睡著了一般。 火紅的嫁衣襯著肌膚如雪当凡。 梳的紋絲不亂的頭發(fā)上山害,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天纠俭,我揣著相機(jī)與錄音,去河邊找鬼浪慌。 笑死冤荆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的权纤。 我是一名探鬼主播钓简,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼汹想!你這毒婦竟也來了外邓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤古掏,失蹤者是張志新(化名)和其女友劉穎损话,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體槽唾,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丧枪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庞萍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豪诲。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖挂绰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情服赎,我是刑警寧澤葵蒂,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站重虑,受9級特大地震影響践付,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缺厉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一永高、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧提针,春花似錦命爬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗜价,卻和暖如春艇抠,著一層夾襖步出監(jiān)牢的瞬間幕庐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工家淤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留异剥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓絮重,卻偏偏與公主長得像冤寿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子绿鸣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355