如果不知道正則表達(dá)式是什么俏扩,可以看一下此篇入門文章
關(guān)于正則中的表達(dá)式符號(hào)和特殊字符,可以看此速查表,部分內(nèi)容與python的擴(kuò)展寫法有些出入
自己寫的正則表達(dá)式,也可以用此工具校驗(yàn)一下
python中的一些擴(kuò)展寫法籽前,和速查表的內(nèi)容有出入的
擴(kuò)展寫法.png
常見(jiàn)的正則表達(dá)式屬性.png
該文章所使用的python版本為3.5.2
在python中,是使用re模塊來(lái)支持正則表達(dá)式的敷钾,使用該模塊時(shí)枝哄,直接引入即可
import re
-
match()函數(shù)與search()工作
- match()函數(shù)試圖從字符串的起始部分對(duì)模式進(jìn)行匹配
- search()的工作方式與 match()完全一致,不同之處在于 search()會(huì)用它的字符串參數(shù)闰非,在任意位置對(duì)給定正則表達(dá)式模式搜索第一次出現(xiàn)的匹配情況膘格。如果搜索到成功的匹配,就會(huì)返回一個(gè)匹配對(duì)象财松; 否則瘪贱, 返回
m = re.match('foo', 'foo')
if m: print(m.group()) # 輸出為: foo
m = re.match('foo', 'seafood') # match只能從起始字符串開始匹配的,所以返回m的值為None
m = re.search('foo', 'seafood')
if m: print(m.group()) # 輸出: foo
-
findall()函數(shù)和finditer()函數(shù)
- findall()查詢字符串中某個(gè)正則表達(dá)式模式全部的非重復(fù)出現(xiàn)情況,返回的是一個(gè)list
- finditer()與findall()類似辆毡,不過(guò)返回的是一個(gè)迭代器而已
s = 'This and that. the and thirty'
print(re.findall(r'(th\w+) and (th\w+)', s, re.I)) # 輸出: [('This', 'that'), ('the', 'thirty')]
-
sub()函數(shù)和subn()函數(shù)
- 這兩個(gè)函數(shù)是用于實(shí)現(xiàn)搜索和替換功能
- subn()和 sub()作用一樣菜秦,sub()返回替換后的字符串,但 subn()還返回一個(gè)表示替換的總數(shù)舶掖,替換后的字符串和表示替換總數(shù)的數(shù)字一起作為一個(gè)擁有兩個(gè)元素的元組返回球昨。
ret = re.sub('X', 'Mr.Smith', 'attn: X\n\nDear X, \n')
print(ret) # 'attn: Mr.Smith\n\nDear Mr.Smith, \n'
ret = re.subn('X', 'Mr.Smith', 'attn: X\n\nDear X, \n')
print(ret) # ('attn: Mr.Smith\n\nDear Mr.Smith, \n', 2)
-
split()函數(shù)
e 模塊和正則表達(dá)式的對(duì)象方法 split()對(duì)于相對(duì)應(yīng)字符串的工作方式是類似的,但是與分割一個(gè)固定字符串相比眨攘,它們基于正則表達(dá)式的模式分隔字符串主慰,為字符串分隔功能添加一些額外的威力
DATA = (
'Mountain View, CA 94040',
'Sunnyvale, CA',
'Los Altos, 94023',
'Cupertino 95014',
'Palo Alto CA',
)
for datanum in DATA:
s = re.split(', |(?= (?:\d{5}|[A-Z]{2})) ', datanum) # 依據(jù)城市名或者編碼拆分嚣州,正則的含義:依據(jù)", "(逗號(hào)空格)拆分或者依據(jù)空格(該空格的左側(cè)是5個(gè)數(shù)字或者是2個(gè)大寫字母)
print(s)
結(jié)果:
['Mountain View', 'CA', '94040']
['Sunnyvale', 'CA']
['Los Altos', '94023']
['Cupertino', '95014']
['Palo Alto', 'CA']
-
一些示例
簡(jiǎn)單的郵箱地址匹配
patt = '\w+@(\w+\.)?\w+\.com' # 只能匹配@后面,類似于xxx.com/xxxx.yyy.com的郵箱
m = re.match(patt, 'nobody@xxx.yyy.com')
patt = '\w+@(\w+\.)*\w+\.com' # 匹配@后面有多個(gè)域名的郵箱共螺,類似xxx.xxx.xxx.xxx...com
m = re.match(patt, 'nobody@xxx.yyy.zzz.com')
group()函數(shù)的一些示例
re.match('(ab)', 'ab') # group()==group(1) 相等
re.match('(a)(b)', 'ab') # group():ab group(1):a group(2):b
re.match('(a(b))', 'ab') # group():ab group(1):ab group(2):b
re.match('((a)(b))', 'ab') # group():ab group(1):ab group(2):a goup(3):b
m = re.search(r'\bthe', 'bite the dog') # \b匹配的是單詞邊界
m = re.search(r'the\b', 'bitethe dog')
m = re.search(r'\Bthe', 'bitethe dog') # 匹配左側(cè)沒(méi)有邊界的the
使用re.x編寫易于查看的正則表達(dá)式
# 編寫易于查看的正則表達(dá)式
# re.X/VERBOSE 標(biāo)記非常有趣该肴;該標(biāo)記允許用戶通過(guò)抑制在正則表達(dá)式中使用空白符(除了在字符類中或者在反斜線轉(zhuǎn)義中)來(lái)創(chuàng)建更易讀的正則表達(dá)式
m = re.search(r'''(?x)
\((\d{3})\)
[ ]
(\d{3})
-
(\d{4})
''', '(800) 555-1212') # 其實(shí)和這個(gè)等價(jià)了m = re.search(r'\((\d{3})\)[ ](\d{3})-(\d{4})','(800) 555-1212'),但是更易于看
# 還可以使用\N藐不,其中 N 是在替換字符串中使用的分組編號(hào)
# 將 2/20/91 換成 1991-02-20
m = re.sub(r'(\d{1,2})/(\d{1,2})/(\d{2}|\d{4})', r'19\3-0\1-\2', '2/20/91')
指定group()分組的名稱
# (?P<name>) 和 (?P=name)
# 前者通過(guò)使用一個(gè)名稱標(biāo)識(shí)符而不是使用從 1 開始增加到 N 的增量數(shù)字來(lái)保存匹配匀哄,
# 如果使用數(shù)字來(lái)保存匹配結(jié)果,我們就可以通過(guò)使用\1,\2 ...,\N \來(lái)檢索, 可以查看上一個(gè)示例
# 大概意思就是: 原來(lái)的分組雏蛮,默認(rèn)的用group(1),group(2)...去取結(jié)果涎嚼,現(xiàn)在用group('xxx')去取
m = re.search(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?:\d{4})', '(900) 555-1212 abc (600) 666-9898')
print(m.groupdict()) # 輸出: {'areacode': '900', 'prefix': '555'}
print(m.group()) # 輸出: (900) 555-1212
print(m.group(1), m.group('areacode')) # 輸出:900 900
m = re.sub(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(\d{4})', r'\g<areacode> \g<prefix>-xxxx', '(900) 666-1212')
print(m) # 輸出: 900 666-xxxx
m = re.sub(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(\d{4})', r'\1 \2-xxxx', '(900) 666-1212') # 與上面的等價(jià)
print(m)
指定分組名,并且易于查看的正則表達(dá)式
# 下面這種寫法挑秉,太長(zhǎng)法梯,看著太費(fèi)勁
m = re.match(
r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?P<number>\d{4}) (?P=areacode)-(?P=prefix)-(?P=number) 1(?P=areacode)(?P=prefix)(?P=number)',
'(800) 555-1212 800-555-1212 18005551212')
print(bool(m))
# 使用(?x)優(yōu)化
m = re.match(r'''(?x)
# 匹配 (800) 555-1212
\((?P<areacode>\d{3})\)[ ](?P<prefix>\d{3})-(?P<number>\d{4})
# 匹配空格
[ ]
# 匹配 800-500-1212
(?P=areacode)-(?P=prefix)-(?P=number)
# 匹配空格
[ ]
#匹配18005551212
1(?P=areacode)(?P=prefix)(?P=number)
''', '(800) 555-1212 800-555-1212 18005551212')
print(bool(m))
一串?dāng)?shù)字,每三個(gè)之間加上一個(gè)分隔符
# 給一串?dāng)?shù)字衷模,每三位添加一個(gè)'-'
data = '1234567890'
patt = r'((?<=\d)\d{3})+\b'
m = re.search(patt, data)
while m:
data = data[:m.start()] + '-' + data[m.start():]
m = re.search(patt, data)
print('添加"-"完畢鹊汛,結(jié)果為:', data)
識(shí)別時(shí)間
# 左邊不能是數(shù)字,右邊也不能是數(shù)字
patt = r'(?<!\d)(2[0-3]{1}|[01]?[0-9]{1}):([0-5]?[0-9]{1}):([0-5]?[0-9]{1})(?!\d)'
m = re.search(patt, 'asc 19:23:23 adfs')
print(m.group(1), m.group(2), m.group(3))