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

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

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

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

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

當然也有些任務可以用正則表達式完成,不過最終表達式會變得異常復雜。碰到這些情形時,編寫Python 代碼進行處理可能反而更好;盡管 Python 代碼比一個精巧的正則表達式要慢些,但它更易理解。


常用方法

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

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

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

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

re.sub: 匹配字符并替換

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



基本模式

簡單字符

沒有特殊意義的字符都是簡單字符,簡單字符就代表自身,絕大部分字符都是簡單字符,舉個例子

/abc/ //匹配 abc

/123/ //匹配 123

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


轉義字符

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

第二種,正則中預先定義了一些代表特殊意義的字符,比如\w等

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


字符集合

有時我們需要匹配一類字符,字符集可以實現這個功能,字符集的語法用[]分隔,下面的代碼能夠匹配a或b或c

[abc]

如果要表示字符很多,可以使用-表示一個范圍內的字符,下面兩個功能相同

[0123456789]

[0-9]

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

[^abc]

其實正則還內置了一些字符集,在上面的轉義字符有提到,下面給出內置字符集對應的自定義字符集

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

\w = [0-9a-Z_]

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

\s = [ \t\n\v]

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

\d = [0-9]

\D = [^0-9]

量詞

如果我們有三個蘋果,我們可以說自己有個3個蘋果,也可以說有一個蘋果,一個蘋果,一個蘋果,每種語言都有量詞的概念

如果需要匹配多次某個字符,正則也提供了量詞的功能,正則中的量詞有多個,如?、+、*、{n}、{m,n}、{m,}

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

{m, n}匹配m-n次,優先匹配n次,比如a{1,3},可以匹配aaa、aa、a

{m,}匹配m-∞次,優先匹配∞次,比如a{1,},可以匹配aaaa...

?匹配0次或1次,優先匹配1次,相當于{0,1}

+匹配1-n次,優先匹配n次,相當于{1,}

*匹配0-n次,優先匹配n次,相當于{0,}

正則默認和人心一樣是貪婪的,也就是常說的貪婪模式,凡是表示范圍的量詞,都優先匹配上限而不是下限

a{1, 3} //匹配字符串'aaa'的話,會匹配aaa而不是a

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

a{1, 3}? //匹配字符串'aaa'的話,會匹配a而不是aaa

字符邊界

有時我們會有邊界的匹配要求,比如已xxx開頭,已xxx結尾

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

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

$表示匹配結尾的意思

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

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

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

選擇表達式

有時我們想匹配x或者y,如果x和y是單個字符,可以使用字符集,[abc]可以匹配a或b或c,如果x和y是多個字符,字符集就無能為力了,此時就要用到分組

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

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

分組和引用

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

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

分組不能放在[]中,分組中還可以使用選擇表達式

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

和分組相關的概念還有一個捕獲分組和非捕獲分組,分組默認都是捕獲的,在分組的(后面添加?:可以讓分組變為非捕獲分組,非捕獲分組可以提高性能和簡化邏輯

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

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

和分組相關的另一個概念是引用,比如在匹配html標簽時,通常希望后面的xxx能夠和前面保持一致

引用的語法是\數字,數字代表引用前面第幾個捕獲分組,注意非捕獲分組不能被引用

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

預搜索

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

js只支持先行預搜索,也就是xxx前面必須是yyy,或者xxx前面不能是yyy

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

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

修飾符

默認正則是區分大小寫,這可能并不是我們想要的,正則提供了修飾符的功能,修復的語法如下

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

g正則遇到第一個匹配的字符就會結束,加上全局修復符,可以讓其匹配到結束

i正則默認是區分大小寫的,i可以忽略大小寫

m正則默認遇到換行符就結束了,不能匹配多行文本,m可以讓其匹配多行文本



主要方法

re.compile方法

compile 函數用于編譯正則表達式,生成一個正則表達式( Pattern )對象,供 match() 和 search() 這兩個函數使用。

語法:

re.compile(pattern[, flags])


pattern :一個字符串形式的正則表達式

flags :可選,表示匹配模式,比如忽略大小寫,多行模式等,具體參數為:

re.I忽略大小寫

re.L表示特殊字符集 \w, \W, \b, \B, \s, \S依賴于當前環境

re.M多行模式

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

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

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

上述flags re.I和re.M是非常常用的。如果要同時使用兩個flags,可以使用re.I | re.M。


例子:
我們編寫了一個電子郵箱的正則表達式,并用它來驗證用戶輸入的郵箱是否有效。

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 :一個字符串形式的正則表達式

string :要匹配的字符串


例子:
編寫了一個年份的正則表達式

import re


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

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是從頭匹配的,從頭沒有符合正則表達式,就返回None。

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


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


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開始。


有的符號如", ', )本身就有特殊的含義,我們在正則表達中使用時必需先對它們進行轉義,方法就是在其符號前件反斜杠\。

下例展示了我們如何從“總共樓層(共7層)"提取共7層三個字,我們需要給括號轉義。

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中我們還使用了一對沒加反斜杠的括號,表明這是一個match group。


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

import re

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

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

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

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

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

(共7層)干擾)

(共7層)

Python里正則匹配默認是貪婪的,總是嘗試匹配盡可能多的字符。

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


re.findall方法

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

findall方法使用方法有兩種,一種是pattern.findall(string) ,另一種是re.findall(pattern, string)。

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


語法:

pattern.findall(string)

re.findall(pattern, string)

pattern : 一個字符串形式的正則表達式

string : 要匹配的字符串


例子:
提取年份列表

import re

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

string1 ='我愛1998和1999年'

print(year_pattern.findall(string1))

['1998', '1999']


提取百度首頁帶有鏈接的關鍵詞

import re

import requests


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

response.encoding="utf-8"

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

for urlin urls:

print(url)

登錄

意見反饋


re.sub方法

該方法經常用于去除空格,無關字符或隱藏敏感字符。

語法:

re.sub(pattern, new_string, current_string)

pattern :一個字符串形式的正則表達式

new_string :要替換的字符串

current_string :要匹配的字符串


實例:
如何把年份替換為****

import re

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

string1 ='我愛1998和1999年'

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

print(replaced_str)

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


re.split方法

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

語法:

re.split(pattern, string)

pattern :一個字符串形式的正則表達式

string :要匹配的字符串


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

import re

string1 ="1cat2dogs3cats4"

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

print(list1)

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

列表首尾都多了空格,需要手動去除。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373