預編譯
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<name>) : 在上面分組的基礎上 起別名
(?P=name) : 根據分組的別名來使用分組
eg:
s = '<h1>你好</h1>'
r1 = re.compile(r'<(?P<name1>\w+)>(\w+)</(?P=name1)>').match(s).group(2)
print(r1)
>>> 你好
\數字 :提取的分組能夠在 同一個正則中 複用
eg:
s = '<h1>你好</h1>'
r1 = re.compile(r'<(\w+)>(\w+)</\1>') # \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)