一、正則表達式
1. 什么是正則表達式
正則表達式是處理字符串的工具,通過不同的正則符號來描述字符串的規則
2. 正則符號(正則表達式的語法)
1) 普通字符(普通字符代表字符本身)
除了在正則中有特殊功能和特殊意義的符號以外的字符都是普通字符
# 匹配一個字符串有三個字符,分別是'a', 'b', 'c'
re_str = 'abc'
result = fullmatch(re_str, 'abc')
print(result) # <_sre.SRE_Match object; span=(0, 3), match='abc'>
2) .
匹配任意一個字符, 一個.
只能匹配一個字符
# 匹配一個字符串長度是8,前三個字符是abc,后三個字符是123,中間任意兩個字符
re_str = r'abc..123'
result = fullmatch(re_str, 'abc-+123')
print(result) # <_sre.SRE_Match object; span=(0, 8), match='abc-+123'>
3) \w
匹配一個數字、字母或者_(在ASCII碼表中), 一個\w
只能匹配一個字符
# 匹配一個長度是4的字符串,第一個字符是數字、字母或者_,后三個字符是abc
re_str = r'\wabc'
result = fullmatch(re_str, '_abc')
print(result) # <_sre.SRE_Match object; span=(0, 4), match='_abc'>
4) \d
匹配任意一個數字字符, 一個\d
只能匹配一個字符
# 匹配一個長度是5的字符串,前兩個字符是任意數字,后面三個是任意字符
re_str = r'\d\d...'
result = fullmatch(re_str, '12sfa')
print(result) # <_sre.SRE_Match object; span=(0, 5), match='12sfa'>
5) \s
匹配任意一個空白字符, 一個\s
只能匹配一個字符
空白字符包括空格,換行符,制表符等
result = fullmatch(r'how\sare!', 'how are!')
print(result) # <_sre.SRE_Match object; span=(0, 8), match='how are!'>
6) \大寫字母
\D
匹配除了數字字符以外的任意字符(匹配一個非數字字符)
\S
匹配一個非空白字符
re_str = r'\Dabc\S'
print(fullmatch(re_str, '+abc1')) # <_sre.SRE_Match object; span=(0, 5), match='+abc1'>
7) [字符集]
匹配字符集中出現的任意一個字符
注意
:一個[]
只能匹配一個字符
a.
[abc]
匹配abc中任意一個字符
# 匹配一個長度是4的字符串,第一個字符是1或3或7,后三個字符是abc
re_str = r'[137]abc'
print(fullmatch(re_str, '1abc')) # <_sre.SRE_Match object; span=(0, 4), match='1abc'>
print(fullmatch(re_str, '2abc')) # None
b.
[1-9]
匹配1~9中的任意一個字符(字符編碼值遞增)
[a-z
] 匹配任意一個小寫字母
[A-Z]
匹配任意一個大寫字母
[a-zA-Z]
匹配任意一個字母
[a-zA-Z\d_]
匹配任意一個字母、數字或_
[ \t\n]
匹配任意一個空白字符
[\u4e00-\u9fa5]
匹配任意一個中文字符
re_str = r'[!-&]123'
print(fullmatch(re_str, '$123')) # <_sre.SRE_Match object; span=(0, 4), match='$123'>
print(fullmatch(re_str, '(123')) # None
re_str = r'[a-zA-Z\d_]==='
print(fullmatch(re_str, '1===')) # <_sre.SRE_Match object; span=(0, 4), match='1==='>
print(fullmatch(re_str, 'W===')) # <_sre.SRE_Match object; span=(0, 4), match='W==='>
# print(fullmatch(r'[z-a]', 'a')) # sre_constants.error: bad character range z-a at position 1
8) [^字符集]
匹配不在字符集中的任意一個字符
[^abc]
匹配任意一個不是a,b,c的字符
[^2-8]
匹配任意一個不是數字2-8的字符
[^\u4e00-\u9fa5]
匹配任意一個非中文字符
re_str = r'[^2-8]abc'
print(fullmatch(re_str, '0abc')) # <_sre.SRE_Match object; span=(0, 4), match='0abc'>
print(fullmatch(re_str, '5abc')) # None
2. 檢測符號
所有的檢測符號都不會影響字符串的長度
1) \b
:檢查是否是單詞邊界
單詞邊界指的是能夠將兩個單詞隔開并且不會產生歧義的任意符號(空白字符、標點符號、字符串開頭和字符串結尾)
匹配規則: 先去掉\b
對字符串進行匹配,如果匹配成功再檢查\b所在的位置是否是單詞邊界
# 匹配一個長度為6的字符串,每個字符分別是a,b,c,1,2,3,并且要求abc和123之間是單詞邊界
re_str = r'abc\b123'
print(fullmatch(re_str, 'abc123')) # None
re_str = r'abc\b,123'
print(fullmatch(re_str, 'abc,123')) # <_sre.SRE_Match object; span=(0, 7), match='abc,123'>
print(search(r'\d\d', 'sf86sfs 67 =--')) # <_sre.SRE_Match object; span=(2, 4), match='86'>
print(search(r'\b\d\d\b', 'sf86sfs 67 =--')) # <_sre.SRE_Match object; span=(8, 10), match='67'>
2) ^
:檢查^
所在的位置是否是字符串開頭
注意
:這里的^
要在[]
外面
re_str = r'^\d\d\d'
print(fullmatch(re_str, '345')) # <_sre.SRE_Match object; span=(0, 3), match='345'>
print(search(re_str, 'dasfa345sdh982==654==')) # None
print(findall(re_str, '345sdh982==654==')) # ['345']
print(search(r'^\d\d\d', '345')) # <_sre.SRE_Match object; span=(0, 3), match='345'>
3) $
:檢查$
所在的位置是否是字符串結尾
re_str = r'\d\d\d$'
print(fullmatch(re_str, '345')) # <_sre.SRE_Match object; span=(0, 3), match='345'>
print(search(re_str, 'dasfa345sdh982==654==124')) # <_sre.SRE_Match object; span=(21, 24), match='124'>
print(findall(re_str, '345sdh982==654==123')) # ['123']
3. 控制次數的符號
1) *
匹配0次或多次
123a*
123后面a出現0次或多次(123,123a,123aa)
123\d*
123后面出現0個或者多個任意數字字符(123,1230,12311)
123[mnxy9]*
123,123m,123mmn,12399
re_str = r'abc0*123'
print(fullmatch(re_str, 'abc00123')) # <_sre.SRE_Match object; span=(0, 8), match='abc00123'>
2) +
匹配1次或多次
123a+ 匹配123a,123aa,123aaa...
re_str = r'123[a-z]+'
print(fullmatch(re_str, '123iyujh')) # <_sre.SRE_Match object; span=(0, 8), match='123iyujh'>
3) ?
匹配0次或1次
-?123 匹配123/-123
re_str = r'_?abc'
print(fullmatch(re_str, 'abc')) # <_sre.SRE_Match object; span=(0, 3), match='abc'>
print(fullmatch(re_str, '_abc')) # <_sre.SRE_Match object; span=(0, 4), match='_abc'>
4) {}
{N}
匹配N次a{3} 匹配3個a
\d{3} 匹配任意3個數字,345,344,000...
{M, N}
匹配M~N次(至少M次,至多N次)
{M,}
匹配至少M次
{, N}
匹配至多N次
# 匹配電話號碼
re_str = r'1[3-9]\d{9}'
# 匹配密碼,要求是6-12位的數字或者字母
re_str = r'[a-zA-Z\d]{6,12}'
print(fullmatch(r'123a{2,4}', '123aa')) # <_sre.SRE_Match object; span=(0, 5), match='123aa'>
print(fullmatch(r'123a{2,4}', '123a')) # None
5) 貪婪和非貪婪
在匹配次數不確定時,會出現貪婪和非貪婪兩種情況:默認情況都是貪婪
貪婪:在能夠匹配成功的情況下,匹配次數盡可能多
非貪婪:在能夠匹配成功的情況下,匹配次數盡可能少(在匹配次數后加?
)
re_str = r'a.+'
print(search(re_str, 'hsjsa==2-32')) # <_sre.SRE_Match object; span=(4, 11), match='a==2-32'>
print(search(r'a.+?', 'hsjsa==2-32')) # <_sre.SRE_Match object; span=(4, 6), match='a='>
re_str = r'a.+b'
print(search(re_str, 'a234b123b123')) # <_sre.SRE_Match object; span=(0, 9), match='a234b123b'>
re_str = r'a.+?b'
print(search(re_str, 'a234b123b123')) # <_sre.SRE_Match object; span=(0, 5), match='a234b'>
4. 分支和分組
1) |
分支
正則1|
正則2 : 先讓正則1匹配,如果匹配成功就成功,匹配失敗再讓正則2匹配(正則1和正則2中只要有一個能匹配成功即可)
re_str = r'abc|123'
print(fullmatch(re_str, 'abc')) # <_sre.SRE_Match object; span=(0, 3), match='abc'>
print(fullmatch(re_str, '123')) # <_sre.SRE_Match object; span=(0, 3), match='123'>
re_str = r'\d{2,5}|[a-z]+123'
print(fullmatch(re_str, '2141')) # <_sre.SRE_Match object; span=(0, 4), match='2141'>
print(fullmatch(re_str, 'a123')) # <_sre.SRE_Match object; span=(0, 4), match='a123'>
練習1:寫一個正則表達式,要求匹配一個字符串:abc的前面是兩個數字或者兩個大寫字母
# 方法1
re_str = r'\d{2}abc|[A-Z]{2}abc'
print(fullmatch(re_str, '41abc')) # <_sre.SRE_Match object; span=(0, 5), match='41abc'>
print(fullmatch(re_str, 'QWabc')) # <_sre.SRE_Match object; span=(0, 5), match='QWabc'>
2)()
分組: 將()中的內容作為一個整體
a. 整體操作
r'(\d|[A-Z]){2}abc' : 匹配一個字符串,后面是abc,前面是兩個數字或者兩個大寫字母
r'([a-zA-Z]\d){3}' : 字母數字重復3次
b. 分組
分組截取:方面后面分段或者分情況取不同的匹配結果
re_str = r'(\d{3})[a-z]{3}'
print(fullmatch(re_str, '344hsj')) # <_sre.SRE_Match object; span=(0, 6), match='344hsj'>
print(findall(re_str, 'sdf345賽風weg568lkjoik==789wer--899fdsf')) # ['568', '789', '899']
分組重復:在正則中用\X重復第X個分組匹配到的內容
re_str = r'(\d{3})[a-z]{3}\1'
print(fullmatch(re_str, '123abc123')) # <_sre.SRE_Match object; span=(0, 9), match='123abc123'>
print(fullmatch(re_str, '123abc122')) # None
re_str = r'(\d{3})([a-z]{3})\2'
print(fullmatch(re_str, '123abcsaf')) # None
print(fullmatch(re_str, '123abcabc')) # <_sre.SRE_Match object; span=(0, 9), match='123abcabc'>
注意
:\X的前面必須有這個分組
5. 轉義符號
1) 加\
在正則中有特殊功能和特殊意義的符號前加\
,讓這個符號的特殊功能和意義消失
re_str = r'\d{3}\.[a-z]{3}'
print(fullmatch(re_str, '111.abc')) # <_sre.SRE_Match object; span=(0, 7), match='111.abc'>
print(fullmatch(re_str, '111=abc')) # None
re_str = r'a\+\d{3}'
print(fullmatch(re_str, 'a+123')) # <_sre.SRE_Match object; span=(0, 5), match='a+123'>
print(fullmatch(re_str, 'a0123')) # None
2) 加[]
在[]
中有特殊意義的符號: a. ^
放在最開頭; b. -
放在兩個字符中間
其它符號包括:.
,+
,?
,*
,$
這些單獨的符號在[]
中都表示這個符號本身
re_str = r'\d{3}[.][a-z]{3}'
print(fullmatch(re_str, '123.ada')) # <_sre.SRE_Match object; span=(0, 7), match='123.ada'>
print(fullmatch(re_str, '123_ada')) # None
二、re模塊
re模塊是python提供的,專門針對正則表達式應用的相關函數
1. compile(正則表達式) : 將正則表達式轉換成正則對象
re_obj = compile(r'\d{3}')
fullmatch(r'\d{3}', '347')
re_obj.fullmatch('347')
2.字符串匹配
fullmatch(正則表達式, 字符串) : 讓正則表達式和字符串完全匹配
match(正則表達式, 字符串) : 匹配字符串開頭
以上兩個方法的結果:匹配失敗結果是None, 匹配成功會返回匹配對象
re_str = '\d{3}'
print(fullmatch(re_str, '783sdfs')) # None
print(match(re_str, '783sdfs')) # <_sre.SRE_Match object; span=(0, 3), match='783'>
1) 匹配對象
a. 獲取匹配到的字符串
匹配對象.group() : 獲取整個正則表達式匹配到的字符串,結果是字符串
匹配對象.group(N) : 獲取整個正則表達式中第N個分組匹配到的字符串
result = fullmatch(r'(\d{3})=([a-z]{2})', '234=am')
print(result) # <_sre.SRE_Match object; span=(0, 6), match='234=am'>
print(result.group()) # 234=am
print(result.group(1)) # 234
print(result.group(2)) # am
b. 獲取匹配到的字符串在原字符串中的位置信息
匹配對象.span() : 返回匹配結果在原字符串中的下標范圍[開始下標, 結束下標)
匹配對象.span(N) : 返回第N個分組的匹配結果在原字符串中的下標范圍[開始下標, 結束下標)
print(result.span()) # (0, 6)
print(result.span(2)) # (4, 6)
c. 獲取原字符串
匹配對象.string
print(result.string) # 234=am
3. 查找
1)search(正則表達式, 字符串)
在字符串中查找第一個滿足正則表達式的子串,如果找到結果是匹配對象,否則是None
result = search(r'\d{3}', '324ggs+++325hsdf')
print(result) # <_sre.SRE_Match object; span=(0, 3), match='324'>
2)findall(正則表達式, 字符串)
獲取字符串中所有滿足正則表達式的子串;返回值是一個列表
result = findall(r'\d{3}[a-z]{2}', 's234hu賽跟隨345mmkxv89h-=數348jl僧二維表')
print(result) # ['234hu', '345mm', '348jl']
result = findall(r'(\d{3})[a-z]{2}', 's234hu賽跟隨345mmkxv89h-=數348jl僧二維表')
print(result) # ['234', '345', '348']
result = findall(r'(\d{3})([a-z]{2})', 's234hu賽跟隨345mmkxv89h-=數348jl僧二維表')
print(result) # [('234', 'hu'), ('345', 'mm'), ('348', 'jl')]
注意
:如果正則表達式中有分組,列表中的匹配結果只會取分組匹配到的內容
3)finditer(正則表達式, 字符串)
獲取字符串中所有滿足正則表達式的子串;返回值是一個迭代器,元素是匹配對象
result = finditer(r'(\d{3})([a-z]{2})', 's234hu賽跟隨345mmkxv89h-=數348jl僧二維表')
group = []
group1 = []
group2 = []
for x in result:
group.append(x.group())
group1.append(x.group(1))
group2.append(x.group(2))
print(group, group1, group2) # ['234hu', '345mm', '348jl'] ['234', '345', '348'] ['hu', 'mm', 'jl']
4. 切割
split(正則表達式, 字符串)
將字符串中滿足正則表達式的子串作為切割點,對字符串進行切割;返回一個字符串列表
result = split(r'\d+', '多棱鏡3ja89撒扥撒899SDS')
print(result) # ['多棱鏡', 'ja', '撒扥撒', 'SDS']
5. 替換
sub(正則表達式, 字符串1, 字符串2)
將字符串2中所有滿足正則表達式的子串都替換成字符串1;返回一個字符串
message = 'abc9023'
new_message = sub(r'[b]|[0]', '*', message)
print(new_message) # a*c9*23