預編譯
import re
re1 = re.compile(r'元字符 組成的正則規則') # 元字符下面會說
re1.方法() # 方法下邊也會說
元字符:
表示普通字符:
. # 除了\n外 都可以匹配的到
\d # 只匹配 純數字 0-9
\D # 和 \d相反, 除了數字全都匹配
\s # 只匹配空格
\S # 和 \s相反,除了空格,全都匹配 # 我喜歡用 [\s\S]*? 匹配所有
\w # 只匹配 純數字 或 大小寫字母 或 下劃線
\W # 與 \w 恰好相反, 除了 純數字、大小寫字母、下劃線 全都匹配
[] # [abcde] 只要包含這個列表的字符,都可以匹配的到。但默認只取一個, 簡寫 [a-e]
eg: re.compile(r'[e-h]').match('hello python ').group(0)
>>> h
此外: [^abcde] 或 [^a-e] 表示 '排除',意思就是 除了abcde全匹配
匹配表示邊界的:
^ # 匹配 起始 位置,受 re.M 影響 #注意:不要和 [^123] 除123之外搞混
eg:
import re
r1 = re.compile(r'^\d+')
print(r1.search('456hello123').group())
>>> 456
$ # 匹配 結尾 位置,受 re.M 影響
eg:
import re
s = """
123abc456
678abc789
"""
r1 = re.compile(r'\d+$',re.M) # 注意這里加入了re.M
print(r1.findall(s))
>>> ['456', '789'] # 這是寫了re.M,就意味著 每一行都給你單獨按照規則處理
>>> ['789'] # 如果沒寫re.M, 那么就按照整體,去最后一行的尾部
注: 其實re.M的本質是 是根據\n,進行 斷行,斷行后對每一行按照規則單獨處理
\b: # 匹配 單詞的 邊界(除了 數字、中英字母、下劃線 的 所有符號)
eg:
import re
s = '你好啊----好個P'
r1 = re.compile(r'\b好')
print(r1.findall(s))
>>> 好
# 解釋:這個‘好’是,后面 的那個。因為后面的 ’好‘ 字 左邊是符號,而非單詞字符
\B: # 匹配 單詞 非 邊界(包括 數字、中英字母、下劃線)
eg:
import re
s = '你好啊----好個P'
r1 = re.compile(r'\b好')
print(r1.findall(s))
>>> 好
# 解釋:這個‘好’是,前面 的那個。因為前面的 ’好‘ 字 左邊是中文字符。屬于非邊界
# 所以就匹配上了
再次總結: \b 與 \B:
\b: 匹配邊界字符。邊界字符:(除了 數字、字母、漢字、下劃線的所有符號)
\B: 匹配非邊界字符。非邊界字符:(數字、字母、漢字、下劃線)
匹配表示數量的:
* : 0次 或 多次 eg: 你*
+ : 1次 或 多次 eg: 你+
? : 0次 或 一次 eg: 你?
{m} : 出現m次 eg: 你{3}
{m,} : 至少 出現m次 eg: 你{3,} # 涉及到貪婪模式,不深的不要用
{m,n}: m次 到 n次 之間任意一次就行 eg: 你{3,6}
表示分組:
| : 相當于或運算符, 兩邊寫的是 正則表達式, 優先選擇左邊的
() : 括起來里面的內容,就變成了分組。 可以用 .group(1)提取,如果有更多那就 group(2)..
(?P
) : 在上面分組的基礎上 起別名
(?P=name) : 根據分組的別名來使用分組
eg:
s = '
你好
'
r1 = re.compile(r'<(?P
\w+)>(\w+)').match(s).group(2)
print(r1)
>>> 你好
\數字 :提取的分組可以在 同一個正則中 復用
eg:
s = '
你好
'
r1 = re.compile(r'<(\w+)>(\w+)') # \1 代表復用第一個分組
print(r1.match(s).group(2)) # 2代表提取第二個分組
>>> 你好
匹配模式
re.M # 多行匹配, 影響 ^ 和 $,上面講 ^ 與 $已經詳解了。
re.I # 忽略大小寫
eg:
s = 'aAbB'
r1 = re.compile(r'aabb', re.I).match(s).group()
print(r1)
>>> aAbB
re.S # 提升 . 的權限, 讓 . 可以 匹配到換行符
s = """
hello
python
"""
r1 = re.compile(r'.*', re.S).match(s).group() # 注意這里 re.S
print(r1)
>>> hello
python
注意:如果不寫 re.S 那么 .* 只能匹配到第一行的空字符串,因為遇到第一個空行的\n就停止了
re.X # 可以給正則分行寫,并可以加注釋,
eg:
import re
title = '1好2你3'
r1 = re.compile(r"""
1 # 注釋1 看這兩行
好 # 注釋2 看這兩行,1 和 好 沒有加逗號。但是他們屬于整體的規則,你可以加注釋
""", re.X) # 把正則可以分行寫, 用了re.X后,分行的正則會被看作為一行
result = r1.match(title).group()
print(result) # 輸出結果: 1好
貪婪模式 與 非貪婪模式
個人理解:
貪婪模式:(Python默認使用的就是 貪婪模式)
你想匹配 一個句子中的 一個單詞, 但是你寫的規則恰好可以 滿足 匹配所有單詞。
那么它就會 貪婪的 把所有單詞 全部 都給你匹配出來。 (貪)
使用方法:
* 或 +
非貪婪模式:
即使你把規則寫的很好,并且能把所有字符串都匹配到, 但是如果你加上了 非貪婪模式。
在滿足規則條件的前提下,只匹配一個.
使用方法:
*? 或 +?
eg1:基于search的貪婪模式(match同此)
我們先回憶一下:search()方法的 最核心思想就是:從前往后搜,搜到一個滿足的就直接返回。
OK,繼續。
貪婪:(默認):
import re
r1 = re.compile(r'\d+')
print(r1.search('你好333你好333你好').group())
>>> 333 # 滿足規則后 盡可能貪, 所以第一串連著的 '333' 搜到了就直接返回了
非貪婪(就多了個問號 ? ):
import re
r1 = re.compile(r'\d+?')
print(r1.search('你好333你好333你好').group())
>>> 3 # 嗯,你的規則就是 至少一個數字,搜到了一個就可以返回了,干得漂亮。
eg2: 基于findall的貪婪模式(如果你findall與規則,理解的不透徹,這個會有點繞的,前方高能)
先回憶一下:findall()方法的 最核心思想就是:拿著 定死的 規則,把所有滿足規則的都提出來
OK,繼續。
貪婪(默認):
import re
r1 = re.compile(r'\d+')
print(r1.findall('你好333你好333你好'))
>>> ['333', '333']
解釋: 規則是匹配至少一位數字。
但是 貪婪模式 提醒了 規則:“你的任務是給我盡可能的 多匹配數字”
findall 拿著 被貪婪化的 規則 去匹配原始字符串
被貪婪模式 提醒過的規則果然不負眾望, 一次提一串連著的 ‘333‘
findall 拿著它 提取了 兩次 ,就把所有數字提取出來了
結果就是 ['333', '333']
非貪婪:
import re
r1 = re.compile(r'\d+?')
print(r1.findall('你好333你好333你好'))
>>> ['3', '3', '3', '3', '3', '3']
解釋: 規則 同樣是 匹配至少一位數字。
但是 非 貪婪模式 提醒了 規則:“你的任務是給我盡可能的 少 匹配數字”
findall 拿著 被貪婪化的 規則 去匹配原始字符串
被貪婪模式 提醒過的規則果然不負眾望, 一次只提取一個 ‘3‘
findall 拿著它 提取了 六次 ,才把所有數字提取出來了
結果就是 ['3', '3', '3', '3', '3', '3']
匹配方法
match():
'''
match()方法是 根據規則從第一個開始,向后逐個匹配,如果有一個字符匹配不上,就返回None
'''
s = 'hello python'
re1 = re.compile(r'he')
re1.match('')
result = re1.match(s).group() if re1.match(s) else None # 注意:非None才有group方法
print(result) # 通過 group()方法獲得的才是最終 正則匹配的字符串
>>> he
簡單分組提取:
s = 'hello python'
re1 = re.compile(r'h(e)llo') # 給e加個一個(),就代表添加了分組,一會要把他提出來
result = re1.match(s).group(1) if re1.match(s) else None
# 注意上方的 group(1) 這個參數是1,代表 只 提取 分組 里面的內容
>>> e
# 如果是 group() 或 group(0) 代表提取 整個正則規則 的內容
>>> hello
print(result)
>>> e
嵌套-平行(深度-廣度)分組提取:
原理:分組提取先提取嵌套的,后提取平行的 (專業點就是先深度,后廣度)
eg:
a = '123-%%%-dd'
result = re.compile(r'123(-(%%%)-)d(d)').match(a).groups()
# 或者用 group(1), group(2), group(3) 代替groups() 單個看也行
print(result)
>>> ('-%%%-', '%%%', 'd')
search():
"""
search() 方法是: 從前向后按規則‘搜索’, 直到搜到位置,搜不到就返回None
"""
s = "aaa123aaa"
r1 = re.compile(r'\d+').search(s).group()
print(r1)
>>> 123
findall():
"""
findall() 方法是: 按照正則規則,搜索所有符合規則的字符串,以列表的形式作為結果返回
"""
s = "aaa---123---bbb"
r1 = re.compile(r'\w+').findall(s)
print(r1)
>>> ['aaa', '123', 'bbb']
微不足道的擴展:
a = '123-%%%-dd'
result = re.compile(r'-(.*?)-').findall(a)
print(result)
>>> %%%
# 解釋: findall() 方法中 如果規則中含有分組,那么就會只返回分組中提取的的內容
finditer():
"""
finditer() 和 findall() 使用方式一樣,只不過返回結果是 可迭代對象,easy,此處不在多說
"""
split():
"""
split()方法是:按照規則去切割,切割結果以列表的方式返回
"""
語法關聯:
我們知道字符串 有 split() 方法,可以按照一個參數損耗來切割,但是這個參數只能指定一個
如果讓你在多種規則的前提下切割,需要怎么辦。
巧了,正則切割split() 方法就是解決這個問題的, 實例如下:
s = "aaa%%123@@bbb" # 可以看見,%和@符號把字符分開了,現在我們只想要字符
r1 = re.compile(r'\W+').split(s) # \W 大寫: 以非單詞性字符作為損耗規則,來切割
print(r1)
>>> ['aaa', '123', 'bbb']
sub():
"""
sub()方法是: 按照規則匹配選出代替換的字符,然后自己 給定字符去替換
"""
場景1:常用方式,自己給定目標字符串,按規則匹配并直接替換原始字符串
eg:
s = "aaa%%123@@bbb"
r1 = re.compile(r'\W+').sub('你好',s)
print(r1)
>>> aaa你好123你好bbb
場景2:正則匹配后的結果 經過函數操作,函數的返回值作為 替換的最終結果
eg:
s = "aaa%%123@@bbb"
r1 = re.compile(r'\W+').sub(lambda a:a.group()*2, s)
print(r1)
>>> aaa%%%%123@@@@bbb
解釋: 按照規則匹配到的字符是 %%和@@,經過函數 乘以2后, 就替換成了 %%%%和@@@@
subn():
"""
subn() 和 sub()語法幾乎一樣,唯一的擴展功能就是 返回結果是元組,(字符串, 次數)
"""
s = "aaa%%123@@bbb"
r1 = re.compile(r'\W+').subn('你好',s)
print(r1)
>>> ('aaa你好123你好bbb', 2)
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
