python 之正則表達(dá)式(re模塊)

一. 簡(jiǎn)介

正則表達(dá)式本身是一種小型的,高度專業(yè)的編程語(yǔ)言,二在Python中,通過(guò)內(nèi)嵌集成re 模塊,我們可以直接調(diào)用來(lái)實(shí)現(xiàn)正則匹配.正的表達(dá)式模式被編譯成一些列的字節(jié)碼,然后有C編寫(xiě)的匹配引擎執(zhí)行.
正則表達(dá)式是一種字符串搜索和匹配的工具.
友情鏈接:鬼斧神工之正表達(dá)式

二. 正則表達(dá)式中常用的字符串

1. 普通字符和11個(gè)元字符:

普通字串 匹配自身 abc abc
. 匹配任意除換行符"\n"外的字符(在DOTALL模式中也能匹配換行符 a.b abc
\ 轉(zhuǎn)義字符,使有一個(gè)字符改變?cè)瓉?lái)的意思 a\.c;a\\c a.c;a\c
* 匹配前一個(gè)字符0或多次 abc* ab;abccc
+ 匹配前一個(gè)字符1次或無(wú)線次 abc+ abc;abccc
? 匹配一個(gè)字符0次或1次 abc? ab;abc
^ 匹配字符串開(kāi)頭.在多行匹配每一行的開(kāi)頭 ^abc abc
$ 匹配字符末尾,在多行匹配模式中匹配每一行的末尾 abc$ abc
| 或. 匹配|左右表達(dá)式任意一個(gè),從左到右匹配,如果|沒(méi)有包括在()中,則它的范圍是整個(gè)正則表達(dá)式 abc|def abc def
{} {m}匹配前一個(gè)字符m次,{m,n}匹配前一個(gè)字符m至n次,若省略n,則匹配m至無(wú)限次 ab{1,2}c abc abbc
[] 字符集.對(duì)應(yīng)的位置可以是字符集中任意字符.字符集中的字符的字符可以逐個(gè)列出,也可以給出范圍,如[abc]或[a-c],[^abc]表示取反,即非abc,所有特殊字符在字符集中都失去其原有的特殊含義.用\反斜杠轉(zhuǎn)義恢復(fù)特殊字符的特殊含義 a[bcd]e abe ace ade
() 被括起來(lái)的表達(dá)式將作為分組,從表達(dá)式左邊開(kāi)始沒(méi)沒(méi)遇到一個(gè)分組的左括號(hào)"(",編號(hào)+1.分組表達(dá)式作為一個(gè)整體,可以后接數(shù)量詞.表達(dá)式中的|僅在該組中有效. (abc){2}/a(123|456)c abcabc/a456c

這里需要強(qiáng)調(diào)一下反斜杠\的作用

  • 反斜杠后邊根元字符去除特殊功能;(即將特殊字符轉(zhuǎn)移成普通字符)
  • 反斜杠后邊跟普通字符實(shí)現(xiàn)特殊功能;(即預(yù)定義字符)
  • 引用序號(hào)對(duì)應(yīng)的字組所匹配的字符串.
import re 
a = re.search(r'(tina)(fei)haha\2','tinafeihahafei tinafihahatina').group()
print("結(jié)果:",a)
================
結(jié)果: tinafeihahafei

2. 預(yù)定義字符集(可以寫(xiě)在字符集[...]中)

字符集 含義 示例 結(jié)果
\d 數(shù)字:[0-9] a\dc a1c
\D 非數(shù)字:[^\d] a\Dc abc
\s 匹配任何空白字符:[<空格>\t\r\n\f\v] a\sc a c
\S 非空白字符:[^\s] a\Sc abc
\w 匹配包括下劃線在內(nèi)的任何字符(數(shù)字,字母,下劃線):[A-Za-z0-9_] a\wc abc
\W 匹配非字符字母字符,即匹配特殊字符 a\Wc a c
\A 僅匹配字符串開(kāi)頭,同^ \Aabc abc
\Z 僅匹配字符串結(jié)尾,同$ abc\Z abc
\b 匹配\w和\W之間,即匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置.例如,'er\b'可以匹配"never"中的'er',但不能匹配"verb"中的'er'. \babc\b a\b!bc 空格abc空格 a!bc
\B [^\b] a\Bbc abc
# 這里強(qiáng)調(diào)一下\b的單詞邊界的理解:
import re 
w = re.findall('\btina','tian tinaaaa')
print("結(jié)果是:",w)
s = re.findall(r'\btina','tian tinaaaa')
print("結(jié)果是:",s)
v = re.findall(r'\btina','tian#tianaaaa')
print("結(jié)果是:",v)
a = re.findall(r'\btina\b','tian#tina@aaa')
print("結(jié)果是:",a)
==================
結(jié)果是: []
結(jié)果是: ['tina']
結(jié)果是: ['tina']
結(jié)果是: ['tina']

3. 特殊分組用法:

特殊分組 含義 用法示例 結(jié)果
(?P<name>) 分組,除了原有的編號(hào)外再指定一個(gè)額外的別名 (?P<id>abc){2} abcabc
(?P=name) 引用別名為<name>的分組匹配到字符串 (?P<id>\d)abc(?P=id) 1abc1 5abc5
<number> 引用編號(hào)為<number>的分組匹配到字符串 (\d)abc\1 1abc1 5abc5

三. re模塊中常用的功能函數(shù)

1. compile()

編譯正則表達(dá)式模式,返回一個(gè)對(duì)象的模式.(可以吧那些常用的正則表達(dá)式編譯成正則表達(dá)式對(duì)象,這樣可以提高效率.)

  • 格式:
    re.compile(pattern,flags=0)
    pattern:編譯時(shí)用的表達(dá)式字符串
    flags 編譯標(biāo)志位,用于修改正則表達(dá)式的匹配方式,如:是否區(qū)分大小寫(xiě),多行匹配等.常用的flags有:
標(biāo)志 含義
re.S(DOTALL) 使.匹配包括換行符在內(nèi)的所有字符
re.I (IGNOTECASE) 使匹配對(duì)大小寫(xiě)不敏感
re.L (LOCALE) 做本地化識(shí)別(local-aware匹配,語(yǔ)法等)
re.M(MULTILINE) 多行匹配,影響^和$
re.X(VERBOSE) 該標(biāo)志通過(guò)給予更靈活的格式寫(xiě)得更易于理解
re.U 根據(jù)Unicode字符集解析字符,這個(gè)標(biāo)志影響\w,\W,\b,\B
import re 
tt = "Tom is a good boy, he is cool,clever,and so on ..."
rr = re.compile(r'\w*oo\w*')
print("執(zhí)行結(jié)果是:",rr.findall(tt))   # 查找所有包含'oo'的單詞
================
執(zhí)行結(jié)果是: ['good', 'cool']

2. match()

決定RE是否在字符串剛開(kāi)始的位置匹配. //注:這個(gè)方法并不是完全匹配.當(dāng)pattern結(jié)束時(shí)若string還有剩余字符,仍然是為成功.想要完全匹配,可以在表達(dá)式末尾加上邊界匹配字符'$'

  • 格式"
    re.match(pattern,stting,flags=0)
import re 
a = re.match('com','comwww.runcomoob').group()
print("a的結(jié)果是:",a)
b = re.match('com','Comwww.baidu',re.I)
print("b的結(jié)果是:",b)   # re.I 對(duì)大小寫(xiě)不敏感
========================
a的結(jié)果是: com
b的結(jié)果是: Com

3. search()

re.search() 函數(shù)會(huì)在字符串內(nèi)查找模式匹配,只要找到第一個(gè)匹配然后返回,如果沒(méi)有找到匹配,則返回None.

  • 格式:
    re.search(pattern,strint,flags=0)
import re 
a = re.search('\dcom','www.4comrnuoob.5com').group()
print("a的結(jié)果是:",a)
b  = re.search('com','python.org')
print("b的結(jié)果是:",b)
===================
a的結(jié)果是: 4com
b的結(jié)果是: None
  • 注: match和search一旦匹配成功,就是一個(gè)match object對(duì)象,而match object對(duì)象有以下方法:
    • group() 返回被RE匹配的字符串
    • start() 返回匹配開(kāi)始的位置
    • end() 返回匹配結(jié)束的位置
    • span() 返回一個(gè)元組包含匹配(開(kāi)始,結(jié)束)的位置.
    • group() 返回re整體匹配的字符串,可以一次輸入多個(gè)組號(hào),對(duì)應(yīng)組號(hào)匹配的字符串.
      a.group() 返回re整體匹配的字符串
      b.group(n,m) 返回組號(hào)為n,m所匹配的字符串,如果不存在,則返回indexError異常
      c.group() group方法返回一個(gè)包含正則表達(dá)式中所有小組字符串的元組,從1到所含的小組號(hào),通常group()不需要參數(shù),返回一個(gè)元組,元組中的元就是正則表達(dá)式中定義的組.
import re 
a = "123abc456"
r = re.search('([0-9]*)([a-z]*)([0-9]*)',a)
print("r.group(0)的結(jié)果",r.group(0))
print("r.group(1)的結(jié)果",r.group(1))
print("r.group(2)的結(jié)果",r.group(2))
print("r.group(3)的結(jié)果",r.group(3)) 
#group(1) 列出第一個(gè)括號(hào)匹配部分初斑,group(2) 列出第二個(gè)括號(hào)匹配部分,group(3) 列出第三個(gè)括號(hào)匹配部分日川。
=======================
r.group(0)的結(jié)果 123abc456
r.group(1)的結(jié)果 123
r.group(2)的結(jié)果 abc
r.group(3)的結(jié)果 456

4 . finfall()

re.findall 遍歷匹配,可以獲取字符串中所有的字符串,返回一個(gè)列表.

  • 格式:
    re.findall(pattern,string,flags=0)
import re 
p = re.compile(r'\d+')
r = p.findall('o1n2m3k4')
print("匹配的結(jié)果是:",r)
============
匹配的結(jié)果是: ['1', '2', '3', '4']
import re 
tt = "Jack is a good boy, he is cool,clever,and so on .... "
rr = re.compile(r'\w*oo\w*')
print("rr.findall(tt)匹配的結(jié)果是:",rr.findall(tt))
print("re.findall(r'(\w)*oo(\w)')匹配的結(jié)果是:",re.findall(r'(\w)*oo(\w)',tt))
==================
rr.findall(tt)匹配的結(jié)果是: ['good', 'cool']
re.findall(r'(\w)*oo(\w)')匹配的結(jié)果是: [('g', 'd'), ('c', 'l')]

5. finditer()

搜索string,返回一個(gè)順序訪問(wèn)每一個(gè)匹配結(jié)果(Match對(duì)象)的迭代器.找到RE匹配的所有字符串,并把他們作為一個(gè)迭代器返回.

  • 格式:
    re.finditer(pattern,strint,flags=0)
import re 
iter = re.finditer(r'\d+','12 drumm44ers drumming,11 ... 10 ...  ')
for i in iter:
    print("匹配結(jié)果是:",i)
    print("i.group()匹配結(jié)果是:",i.group())
    print("i.span()匹配結(jié)果是:",i.span())
==========================================
匹配結(jié)果是: <_sre.SRE_Match object; span=(0, 2), match='12'>
i.group()匹配結(jié)果是: 12
i.span()匹配結(jié)果是: (0, 2)
匹配結(jié)果是: <_sre.SRE_Match object; span=(8, 10), match='44'>
i.group()匹配結(jié)果是: 44
i.span()匹配結(jié)果是: (8, 10)
匹配結(jié)果是: <_sre.SRE_Match object; span=(23, 25), match='11'>
i.group()匹配結(jié)果是: 11
i.span()匹配結(jié)果是: (23, 25)
匹配結(jié)果是: <_sre.SRE_Match object; span=(30, 32), match='10'>
i.group()匹配結(jié)果是: 10
i.span()匹配結(jié)果是: (30, 32)

6. split()

按照能夠匹配的字符串將string分割后返回列表.
可以使用re.split來(lái)分割字符串,如:re.split(r'\s','text');將字符串按空格分割成一個(gè)單詞列表.

  • 格式:
    re.split(pattern,string[,maxsplit])
    maxsplit用于指定最大分割次數(shù),不指定將全部分割.
import re 
rr = re.split('\d+','one1two2three3four4five5')
print("rr匹配的結(jié)果是:",rr)
wrr = re.split('[a-z]+','one1two2three3four4five5')
print("wrr匹配的結(jié)果是:",wrr)
================================
rr匹配的結(jié)果是: ['one', 'two', 'three', 'four', 'five', '']
wrr匹配的結(jié)果是: ['', '1', '2', '3', '4', '5']

7. sub()

使用re替換string中每一個(gè)匹配的字符串后返回替換后的字符串.

  • 格式:
    re.sub(pattern,repl,string,count)
    repl:是用什么字符串替換(替換后的字符串)
    count:指的是替換的個(gè)數(shù),默認(rèn)為0,表示每個(gè)都替換.
import re
text = "JGood is a handsome boy, he is cool, clever, and so on..."
rr = re.sub(r'\s+','-',text)
print("替換后的結(jié)果是:",rr)
========================
替換后的結(jié)果是: JGood-is-a-handsome-boy,-he-is-cool,-clever,-and-so-on...

re.sub還允許使用函數(shù)對(duì)匹配項(xiàng)的替換進(jìn)行復(fù)雜的處理.
如:re.sub(r'\s',lambda m:'['+ m.group(0) +']',text,0);將字符串中的空格' '替換為'[]'.

import re 
text  = "JGood is a handsome boy, he is cool, clever, and so on..."
rr = re.sub(r'\s',lambda m:'['+ m.group(0) +']',text,0)
print("替換后的結(jié)果是:",rr)
===========================
替換后的結(jié)果是: JGood[ ]is[ ]a[ ]handsome[ ]boy,[ ]he[ ]is[ ]cool,[ ]clever,[ ]and[ ]so[ ]on...

8. subn()

返回替換次數(shù)

  • 格式:
import re
tt = '123456abcdef'
rr = re.subn('[1-2]','A',tt)
rr1 = re.sub("g.t","have",'I get A,I get B,I get C')
rr2 = re.subn("g.t","have",'I get A,I get B,I get C')
=====================
re.subn()匹配的結(jié)果: ('AA3456abcdef', 2)
re.sub()匹配的結(jié)果: I have A,I have B,I have C
re.subn()匹配的結(jié)果: ('I have A,I have B,I have C', 3)

四. 一些注意點(diǎn)

1. re.match與re.search與re.findall的區(qū)別:

re.match只匹配字符串的開(kāi)始,如果字符串開(kāi)始不符合正則表達(dá)式,則匹配失敗,函數(shù)返回None;而re.search匹配整個(gè)字符串,知道找到一個(gè)匹配.

import re 
a = re.search('[\d]','abc33').group()
print("a匹配的結(jié)果是:",a)
p = re.match('[\d]','abc33')
print("p匹配的結(jié)果是:",p)
b = re.findall('[\d]','abc33')
print("b匹配的結(jié)果是:",b)
============================
a匹配的結(jié)果是: 3
p匹配的結(jié)果是: None
b匹配的結(jié)果是: ['3', '3']

2. 貪婪匹配與非貪婪匹配

?,+?,??,{m,n}? 前面的,+,?等都是貪婪匹配,也就是盡可能匹配,后面加?號(hào)使其邊城惰性匹配

  • 示例一
import re
a = re.findall('a(\d+?)','a23b')
print("a惰性匹配的結(jié)果:",a)
b = re.findall('a(\d+)','a23b')
print("b貪戀匹配的結(jié)果:",b)
==========================
a惰性匹配的結(jié)果: ['2']
b貪戀匹配的結(jié)果: ['23']
  • 示例二
import re 
a = re.match('<(.*)>','<H1>title</H1>').group()
print("a是貪婪匹配的結(jié)果:",a)
b = re.match('<(.*?)>','<H1>title</H1>').group()
print("b是惰性匹配的結(jié)果:",b)
==============================
a是貪婪匹配的結(jié)果: <H1>title</H1>
b是惰性匹配的結(jié)果: <H1>
  • 示例三
    這里需要注意的是如果前后均有限定條件的時(shí)候,就不存在什么貪婪模式了琐谤,非匹配模式失效赡模。
import re 
a = re.findall(r'a(\d+)b','a33333b')
print("a是貪婪匹配的結(jié)果:",a)
b = re.findall(r'a(\d+?)b','a33333b')
print("b是惰性匹配的結(jié)果:",b)
====================
a是貪婪匹配的結(jié)果: ['33333']
b是惰性匹配的結(jié)果: ['33333']

3. 用flags時(shí)遇到的小坑

import re
rr = re.split('a','1A1a2A3',re.I)
print("rr輸出的結(jié)果是:",rr)
================
rr輸出的結(jié)果是: ['1A1', '2A3']

輸出的結(jié)果冰未能區(qū)分大小寫(xiě),這是因?yàn)閞e.split(pattern,string杭跪,maxsplit,flags)默認(rèn)是四個(gè)參數(shù)通惫,當(dāng)我們傳入的三個(gè)參數(shù)的時(shí)候茂翔,系統(tǒng)會(huì)默認(rèn)re.I是第三個(gè)參數(shù),所以就沒(méi)起作用履腋。如果想讓這里的re.I起作用珊燎,寫(xiě)成flags=re.I即可惭嚣。

import re
rr = re.split('a','1A1a2A3',flags=re.I)
print("rr輸出的結(jié)果是:",rr)
=================
rr輸出的結(jié)果是: ['1', '1', '2', '3']

五. 正則匹配的小實(shí)踐

1. 匹配電話號(hào)碼

import re
# 方法一:
phone_pat = re.compile('^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$')
while True:
    phone = input('請(qǐng)輸入你的電話號(hào)碼:')
    res = re.search(phone_pat,phone)
    if res:
       print('正常手機(jī)號(hào)')
    else:
       print('不是手機(jī)號(hào)')
# 方法二
tel_pat = re.compile('^0\d[0-9]{2}|[0-9]{3}-\d[0-9]{8}|[0-9]{7}')
while True:
    tel = input('請(qǐng)輸入你的座機(jī)號(hào):')
    res = re.search(tel_pat,tel)
    # res1 = re.search(tel_pat1,tel)
    if res:
       print('格式正確')
    else:
        print('格式不正確')

2. 匹配IP:

import re 
re.search(r"(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5]\.)","192.168.1.1")

3. 匹配郵箱:

import re  
text = input("Please input your Email address:\n")  
if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$',text):  
#if re.match(r'[0-9a-zA-Z_]{0,19}@163.com',text):  
    print('Email address is Right!')  
else:  
    print('Please reset your right Email address!')  
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悔政,隨后出現(xiàn)的幾起案子晚吞,更是在濱河造成了極大的恐慌,老刑警劉巖谋国,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件槽地,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡芦瘾,警方通過(guò)查閱死者的電腦和手機(jī)捌蚊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)近弟,“玉大人缅糟,你說(shuō)我怎么就攤上這事〉挥洌” “怎么了溺拱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)谣辞。 經(jīng)常有香客問(wèn)我,道長(zhǎng)沐扳,這世上最難降的妖魔是什么泥从? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮沪摄,結(jié)果婚禮上躯嫉,老公的妹妹穿的比我還像新娘。我一直安慰自己杨拐,他們只是感情好祈餐,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哄陶,像睡著了一般帆阳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屋吨,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天蜒谤,我揣著相機(jī)與錄音,去河邊找鬼至扰。 笑死鳍徽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的敢课。 我是一名探鬼主播阶祭,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绷杜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了濒募?” 一聲冷哼從身側(cè)響起鞭盟,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萨咳,沒(méi)想到半個(gè)月后懊缺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡培他,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年鹃两,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舀凛。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俊扳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出猛遍,到底是詐尸還是另有隱情馋记,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布懊烤,位于F島的核電站梯醒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腌紧。R本人自食惡果不足惜茸习,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望壁肋。 院中可真熱鬧号胚,春花似錦、人聲如沸浸遗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)跛锌。三九已至弃秆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間髓帽,已是汗流浹背驾茴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氢卡,地道東北人锈至。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像译秦,于是被迫代替她去往敵國(guó)和親峡捡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子击碗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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