python3基礎:正則(二)
目錄
繼之前總結的正則表示式一些符號後,本節繼續總結如何編譯正則表示式以及編譯後的表示式物件常用的方法/屬性,還有re模組下的相關方法對比
編譯正則表示式
把那些經常使用的正則表示式編譯成正則表示式物件,目的是為了重複利用,這樣可以提高一定的效率。編譯一次之後可以多次使用,還能夠將其序列化。
一般步驟
使用re的一般步驟是先將正則表示式的字串形式編譯為pattern例項,然後使用pattern例項處理文字並獲取匹配結果(一個Match例項),最後使用Match例項獲取資訊進行其他操作。
re.compie
re.compile(pattern, flags=0)
pattern類的工廠方法,將正則表示式pattern編譯成pattern物件,並返回該物件。
引數:第二個引數flag是匹配模式,取值可以使用按位或運算子‘|’表示同時生效,比如re.I和re.M,也可以在regex字串中指定模式,比如:
re.compile('pattern',re.I|re.M)
等價於:
re.compile('(?im)pattern')
程式碼示例:
import re #將正則表示式編譯成Pattern物件 pattern=re.compile(r'hello') #使用Pattern匹配文字,獲取匹配結果,無法匹配時將返回None match=pattern.match('hello world') if match: #獲取分組資訊 print (match.group()) print (match.pos) print (match.endpos)
pattern物件的屬性及方法
pattern物件指的是通過re.compile()函式編譯後得到一個正則表示式,pattern不能直接例項化,必須使用re.compile()函式進行構造。pattern物件的屬性和方法如下:
>>> p = re.compile(r'\d')
>>> dir(p)
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'findall', 'finditer', 'flags', 'fullmatch', 'groupindex', 'groups', 'match', 'pattern', 'scanner', 'search', 'split', 'sub', 'subn']
fags屬性
表示獲取編譯時用的匹配模式,數字形式.通過p.flags我們可以檢視編譯時的選項,不過它顯示的不是字元而是一個整數。
程式碼示例:將正則表示式編譯成Pattern物件
>>> p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
>>> p.flags#compile編譯後用pattern物件的flags得到的是48
48
>>> re.DOTALL #直接列印類屬性re.DOTALL得到的是16
<RegexFlag.DOTALL: 16>
>>> re.match(r'.','\nbds',16) #直接輸入數字和輸入類屬性re.DOTALL是一樣的
<_sre.SRE_Match object; span=(0, 1), match='\n'>
>>> re.match(r".","\ndb",48) #16和48是一樣的效果
<_sre.SRE_Match object; span=(0, 1), match='\n'>
>>> p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', 16)
>>> p.flags#compile編譯後用pattern物件的flags得到的是48
48
groups屬性
獲取正則表示式中分組的個數,也就是括號的組數。
程式碼示例:
>>> p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
>>> p.groups
3
groupindex屬性
以表示式中有別名的組的別名為鍵,其對應的編號為值的字典,沒有別名的組不包含在內
程式碼示例:
# 將正則表示式編譯成Pattern物件
>>> p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
#獲取表示式中所有分組的別名和分組序號組成的字典
>>> p.groupindex
mappingproxy({'sign': 3})
pattern.match()方法
match(string=None, pos=0, endpos=9223372036854775807, *, pattern=None)
函式作用:在字串string的pos位置開始嘗試匹配pattern,如果匹配成功無論是否到達結束位置endpos,都會返回一個匹配成功後的Match物件;如果匹配未成功或者pattern未匹配結束就達到endpos,則返回None。
引數說明:
string:被匹配的字串
pos:匹配的起始位置,可選,預設為0
endpos:匹配的結束位置,可選,預設為len(string)
匹配到的Match物件,使用其group()方法取出匹配結果
程式碼示例:
#encoding=utf-8
import re
p = re.compile(r'\d+')
#不指定匹配區間
m1 = p.match('123abc')
if m1:
print('匹配的內容為:',m1.group())
else:
print('沒有匹配的內容')
#指定匹配區間
m2 = p.match('123abc',2)
if m2:
print('匹配的內容為:',m2.group())
else:
print('沒有匹配的內容')
#指定匹配區間,結束位置超過字串長度,不會報錯
m3 = p.match('123abc',2,10)
if m3:
print('匹配的內容為:',m3.group())
else:
print('沒有匹配的內容')
re.match()方法
match(pattern, string, flags=0)
函式作用:在字串string的起始位置開始嘗試匹配pattern,如果匹配成功返回一個匹配成功後的Match物件;否則返回None。
引數說明:
pattern:匹配的正則表示式
string:被匹配的字串
flags:標誌位,用於控制正則表示式的匹配方式,如是否區分大小寫,是否匹配多行等
區別:該方法與pattern.match()方法的區別在於,它不能指定匹配的區間pos和endpos
程式碼示例:
match=re.match('\d\s\w','1 Abs',re.I)
if match:
print ('匹配的內容為:',match.group())
else:
print ('未找到匹配內容')
pattern.search()方法
search(string=None, pos=0, endpos=9223372036854775807, *, pattern=None)
函式作用:在string[pos,endpos]區間從pos處開始匹配pattern,如果匹配成功,返回匹配成功的Match物件;如果未成功,將pos加1後重新嘗試匹配,直到pos=endpos時仍無法匹配則返回None。
引數說明:
string:被匹配的字串
pos:匹配的起始位置,可選,預設為0
endpos:匹配的結束位置,可選,預設為len(string)
也就是說如果不指定pos和endpos的話,該方法會掃描整個字串匹配到的Match物件,使用其group()方法取出匹配結果
區別:該方法與pattern.match的區別在於,match只匹配字串的開始,如果字串開始不符合正則表示式,則匹配失敗返回None;而search搜尋整個字串,直到知道的一個匹配
程式碼示例:
#encoding=utf-8
import re
#匹配多個數字,最多一個空格,0個或多個單詞字元(字母和數字)
p=re.compile(r'\d+\s?\w*')
#不指定匹配區間
m1 = p.search('12 bcr123Abc123')
if m1:
print ('匹配的內容是:', m1.group())
else:
print ("正則表示式沒有匹配到內容")
#指定匹配區間
m2 = p.search('12 bcr123Abc123',1,10)
if m2:
print ('匹配的內容是:', m2.group())
else:
print ("正則表示式沒有匹配到內容")
#指定匹配區間,結束位置超過字串長度
m3 = p.search('12 bcr123Abc123',3,30)
if m3:
print ('匹配的內容是:', m3.group())
else:
print ("正則表示式沒有匹配到內容")
re.search()方法
search(pattern, string, flags=0)
函式作用:掃描整個字串並返回第一次成功的匹配物件,如果匹配失敗返回None。
區別:該方法與pattern.search的區別在於,它不能指定匹配的區間pos和endpos
引數說明:
pattern:匹配的正則表示式
string:被匹配的字串
flags:標誌位,用於控制正則表示式的匹配方式,如是否區分大小寫,是否匹配多行等
程式碼示例:匹配abc中任一字母,一星號(*),兩個數字
#encoding=utf-8
import re
m = re.search(r'[abc]\*\d{2}','c*2345')
if m:
print('匹配的內容為:',m.group())
else:
print('沒有匹配的內容')
findal()方法
函式作用:查詢字串中所有能匹配的字串,並以結果存於列表中,返回該列表。特殊的地方在於返回的列表中的內容,取決於正則表示式中圓括號的的出現情況,也就是分組情況:
- 當正則表示式中含有多個圓括號()時,返回列表中的元素由所有滿足匹配的內容組成,但是每個元素都是由表示式中所有的圓括號匹配的內容組成的元組。而且元組中元素的個數與括號對數相同,並且字串排放順序和括號中出現的順序一致(一般看左括號’(’就行,字串的內容與每個括號內的正則表示式相對應)
>>> re.findall(r"([a-z])(\d+)","1a2b3c")
[('a', '2'), ('b', '3')]
>>> re.findall(r"([a-z])(\d+)([a-z])","a1ab2bc3")
[('a', '1', 'a'), ('b', '2', 'b')]
>>> re.findall(r"(([a-z])(\d+)([a-z]))","a1ab2bc3c")
[('a1a', 'a', '1', 'a'), ('b2b', 'b', '2', 'b'), ('c3c', 'c', '3', 'c')]
2.當正則表示式中只有一個圓括號時,返回的列表元素由所有成功匹配表示式中圓括號匹配的內容組成,並且該列表中的元素都是字串,它的內容與括號中的正則表示式相對應。(注意:列表中的字串只是圓括號中的內容,不是整個正則表示式所匹配的內容)
>>> re.findall(r"[a-z](\d+)","1a2b3c")
['2', '3']
當正則表示式中沒有圓括號時,返回列表中的元素由所有成功匹配的子串組成
>>> re.findall(r"\d+","1a2b3c")
['1', '2', '3']
pattern.findal()方法
findall(string=None, pos=0, endpos=9223372036854775807, *, source=None)
函式作用:在string[pos,endpos]區間從pos下標開始查詢所有滿足pattern的子串,直到endpos位置結束,並以列表的形式返回查詢的結果,如果未找到則返回一個空列表
引數說明:
string:被匹配的字串
pos:匹配的起始位置,可選,預設為0
endpos:匹配的結束位置,可選,預設為len(string)。也就是說如果不指定pos和endpos的話,該方法會在整個字串中查詢滿足條件的子串。
#程式碼示例1:正則表示式無圓括號時
#找到正則表示式匹配的前10個字母中的所有數字
pattern=re.compile(r'\d+')
match=pattern.findall('o89ne1two2three3four4',0,10)
print (match)
#程式碼示例2:正則表示式有1個圓括號時
#查詢字串中所有的數字子串
matchStr='adsd12343.jl34d5645fd789'
pattern=re.compile(r'.*?(\d+).*?')
result=pattern.findall(matchStr)
print (result)
總結:當正則表示式中只帶有一個圓括號時,列表中的元素為字串,並且該字串的內容與括號中的正則表示式相對應,並且整個返回的結果都是圓括號中的內容,而不是整個正則表示式匹配的內容
程式碼示例3:正則表示式有多個圓括號時
#提取字串中所有的有效的域名地址
add = 'https://www.net.com.edu//action=?asdfsd and other https://www.baidu.com//a=b'
pattern=re.compile(r'((w{3}\.)(\w+\.)+(com|edu|cn|net))')
result = pattern.findall(add)
print (result)
re.findal()方法
findall(pattern, string, flags=0)
函式作用:獲取字串中所有能匹配的字串,並以列表的形式返回。
區別:該方法與pattern.findall的區別在於,它不能指定匹配的區間pos和endpos
引數說明:
pattern:匹配的正則表示式
string:被匹配的字串
flags:標誌位,用於控制正則表示式的匹配方式,如是否區分大小寫,是否匹配多行等
程式碼示例1:正則表示式無圓括號時
#匹配字串中所有含有’oo’字元的單詞
res = re.findall(r'\w*oo\w*', 'woo this foo is too')
print (res)
程式碼示例2:正則表示式有1個圓括號時
#獲取字串中所有的數字字串
res=re.findall(r'.*?(\d+).*?','adsd12343.jl34d5645fd789')
print (res)
程式碼示例3:正則表示式有多個圓括號時
#提取字串中所有的有效的域名地址
add = 'https://www.net.com.edu//action=?asdfsd and other https://www.baidu.com//a=b'
res = re.findall(r'((w{3}\.)(\w+\.)+(com|edu|cn|net))',add)
print (res)
pattern.finditer()方法
finditer(string, pos=0, endpos=9223372036854775807)
函式作用:和findall函式一樣,匹配字串中所有滿足的子串,只是返回的是迭代器,而不是存有所有結果的list,這個迭代器裡面存的是每一個結果的匹配物件,這樣可以節省空間,一般用在需要匹配大量的結果情況下。
引數說明:
string:被匹配的字串
pos: 匹配的起始位置,可選,預設為0
endpos:匹配的結束位置,可選,預設為len(string)。也就是說如果不指定pos和endpos的話,該方法會在整個字串中查詢滿足條件的子串。
程式碼示例:
#encoding=utf-8
import re
p = re.compile(r'[a-z]+',re.I)
for i in p.finditer('one12two34three56four'):
print(i.group())
re.finditer()方法
finditer(pattern, string, flags=0)
函式作用:和findall函式一樣,匹配字串中所有滿足的子串,只是返回的是迭代器,而不是存有所有結果的list,這個迭代器裡面存的是每一個結果的匹配物件,這樣可以節省空間,一般用在需要匹配大量的結果情況下。
引數說明:
pattern:匹配的正則表示式
string:被匹配的字串
flags:標誌位,用於控制正則表示式的匹配方式,如是否區分大小寫,是否匹配多行等
程式碼示例:
#匹配字串中所有連續字母組成的子串
#encoding=utf-8
import re
for i in re.finditer(r'[A-Za-z]+','one12two34three56four'):
print(i.group())
pattern.spit()方法
split(string=None, maxsplit=0, *, source=None)
函式作用:分隔字串,將字串string用給定的正則表示式匹配的字串進行分隔,並返回分隔後的結果列表
引數說明:
string:被匹配的字串
maxsplit :用於指定最大分隔次數,可選,預設為0.表示全部分隔
程式碼示例:
#encoding=utf-8
import re
p = re.compile(r'\d+')
#不指定分割次數
print( p.split('one1two2three3four4'))
#分割3次
print( p.split('one1two2three3four4',3))
re.spit()方法
split(pattern, string, maxsplit=0, flags=0)
函式作用:分隔字串,將字串string用給定的正則表示式匹配的字串進行分隔,並返回分隔後的結果list
引數說明:
pattern:匹配的正則表示式
string:被匹配的字串
maxsplit :用於指定最大分隔次數,可選,預設為0.表示全部分隔
flags:標誌位,用於控制正則表示式的匹配方式,如是否區分大小寫,是否匹配多行等
程式碼示例1:
#encoding=utf-8
import re
#不指定分割次數
print(re.split(r'\d+','one1two2three3four4'))
#分割3次
print( re.split(r'\d+','one1two2three3four4',3))
程式碼示例2:切割出abcd
>>> s = "a 2 b 2 c 5 d"
>>> print( re.split(r'\s+\d\s+',s))
['a', 'b', 'c', 'd']
>>> print( re.split(r'\s+\d\s+',s,2))
['a', 'b', 'c 5 d']
>>> print( re.split(r'\s+\d\s+',s,20))
['a', 'b', 'c', 'd']
pattern.sub()方法
sub(repl, string, count=0)
函式作用:使用repl替換string中的每一個匹配的子串後返回替換後的字串;
當repl是一個字串時,可使用\id或\d<id>、\d<name>引用分組,但不能使用編號0;
當repl是一個方法時,它必須傳一個Match物件,並必須返回一個字串用於替換(返回的字串中不能再引用分組)
引數說明:
repl:用於替換的字串
string:要被替換的字串
count:替換的次數,如果為0表示替換所有匹配到的子串,如果是1表示替換1次,為2替換2次等,該引數必須是非負整數,預設為0
程式碼示例1:repl為字串並使用分組引用
p=re.compile(r'(\w+) (\w+)')#注意中間有空格
s='i say, hello world!'
print (p.findall(s))
#\2,\1表示分組引用,分別代表第二個分組和第一個分組
print (p.sub(r'\2 \1',s))
分析:
"i say,hello word"
一共替換2次:
第一次替換:i say--->分組1:i 分組2:say \2 \1--->say i
say i,hello word
第二次替換:hello word
hello world--->分組1:hello 分組2:world \2 \1--->world hello
最終的替換結果: say I,world hello!
程式碼示例2:repl為方法時,將匹配的結果m傳入方法
#encoding=utf-8
import re
p=re.compile(r'(\w+) (\w+)')#注意中間有空格
def func(m):
return m.group(1).title() +' ' + m.group(2).title()
print (p.sub(func,"i say,hello word"))
程式碼示例3:
#encoding=utf-8
import re
p=re.compile(r'(\w+) (\w+)')
s='i say, hello world!'
#當repl為方法時
def func(m):
print (m)
## print (dir(m))
print (m.string)
print (m.regs) #列印每個分組匹配的內容在字串中的起始座標,左閉右開
print (m.group()) #列印匹配到的全部內容
print (m.group(1)) #列印匹配到的第一個分組的內容
print (m.group(2)) #列印匹配到的第二個分組的內容
return m.group(1).upper()+ m.group(2).upper()
print('\n')
print (p.sub(func,s,1)) #替換一次
print('*'*40)
print (p.sub(func,s))
re.sub()方法
re.sub(pattern, repl, string, count=0, flags=0)
引數說明:
pattern:匹配的正則表示式
repl:用於替換的字串
string:要被替換的字串
count:替換的次數,如果為0表示替換所有匹配到的字串,如果是1表示替換1次,該引數必須是非負整數,預設為0。
flags:標誌位,控制正則表示式的匹配方式。如是否區分大小寫、是否多行匹配等。
程式碼示例1:repl為字串
#encoding=utf-8
import re
#將手機號的後4位替換成0
tel='13549876489'
print(re.sub(r'\d{4}$','0'*4,tel))
#將程式碼後面的註釋資訊去掉
s = 'num=0 # a number'
print(re.sub(r'#.*$','',s))
程式碼示例2:repl為方法
使用add方法作為第二個引數,將匹配到的每個數字作為引數傳入add函式,處理後將返回結果替換為相應字串
#encoding=utf-8
import re
def add(m):
'''將匹配到的數字加10'''
return str(int(m.group())+10)
print(re.sub(r'\d+',add,'1 2 3 4 5'))
程式碼示例3:替換掉字串中的空白字元
>>> re.sub(r'\s','','and \r \n \tn')
'andn'
>>> re.sub(r"[ \t\r]+","","aa 11b b22 \n \t cc")
'aa11bb22\ncc'
pattern.subn()方法
pattern.subn(repl, string[, count = 0])
函式作用:sub函式的用法差不多,只是它返回的是一個tuple,tuple的第一個元素為替換後的新字串,第二個元素是替換的次數。如果想知道替換過程中到底替換了多少次,可以使用subn函式。
程式碼示例1:repl為字串,去掉語句中的特殊符號
#encoding=utf-8
import re
s = "^&&today&(is%%#fine# day!"
p = re.compile(r'[^\w\s]+')
print(p.subn('',s))
程式碼示例2:repl引數為方法時
#encoding=utf-8
import re
print('\n')
def add(m):
'''將匹配到的數字加10'''
return str(int(m.group())+10)
print(re.subn(r'\d+',add,'1 2 3 4 5'))
re.subn()方法
re.subn(pattern, repl, string, count=0, flags=0)
程式碼示例:替換掉除\n外的空白字元
>>> re.subn(r"[ \t\r]+","","aa 11b b22 \n \t cc")
('aa11bb22\ncc', 4)