正規表示式
它是約束字串匹配某種形式的規則
正規表示式有什麼用?
1.檢測某個字串是否符合規則.比如:判斷手機號,身份證號是否合法
2.提取網頁字串中想要的資料.比如:爬蟲中,提取網站天氣,資訊,股票程式碼,星座運勢等具體關鍵字
import re
"""lst = re.findall(正規表示式,字串)"""
正規表示式的種類
正規表示式由一些 [普通字元] 和一些 [元字元] 組成:
(1)普通字元包括大小寫字母和數字
(2)元字元具有特殊含義,大體種類分為如下:
1.預定義字符集,字元組
2.量詞
3.邊界符
4.分組
預定義字符集
預定義字符集 |
匹配內容 |
. |
匹配任意字元,除了換行符\n |
\d |
匹配數字 |
\D |
匹配非數字 |
\w |
匹配字母或數字或下劃線 (正則函式中,支援中文的匹配) |
\W |
匹配非字母或數字或下劃線 |
\s |
匹配任意的空白符 |
\S |
匹配任意非空白符 |
\n |
匹配一個換行符 |
\t |
匹配一個製表符 |
[] |
匹配中括號內列舉的字元 |
# 匹配數字
strvar = "sdjfklj234&*(&1"
lst = re.findall("\d",strvar)
print(lst) #out ['2', '3', '4', '1']
# 匹配非數字
strvar = "YWERsdf78_&"
lst = re.findall("\D",strvar)
print(lst) #out ['Y', 'W', 'E', 'R', 's', 'd', 'f', '_', '&']
# \w 匹配字母或數字或下劃線 (正則函式中,支援中文的匹配)
strvar = "sadf234_^&*%$^$%你好"
lst = re.findall("\w",strvar)
print(lst) #out ['s', 'a', 'd', 'f', '2', '3', '4', '_', '你', '好']
# \W 匹配非字母或數字或下劃線
strvar = "sadf234_^&*%$^$%你好"
lst = re.findall("\W",strvar)
print(lst) #out ['^', '&', '*', '%', '$', '^', '$', '%']
# \s 匹配任意的空白符 ( " " \t \n \r )
strvar = " \r "
lst = re.findall("\s",strvar)
print(lst) #[' ', '\t', '\t', ' ', '\r', ' ']
# \S 匹配任意非空白符
strvar = " \r 123_*("
lst = re.findall("\S",strvar)
print(lst) # out ['1', '2', '3', '_', '*', '(']
# \n 匹配一個換行符
strvar = """
今天國慶假期結束了,兄弟們滿載 而歸,玩的 很困,盡 快調 整.
"""
lst = re.findall(r"\n",strvar)
print(lst) # ['\n', '\n']
strvar = """
今天國慶假期結束了,兄弟們滿載 而歸,玩的 很困,盡 快調 整.
"""
# \t 匹配一個製表符
lst = re.findall(r"\t",strvar)
print(lst) # out 4 \t
字元組格式 |
說明 [預設必須從字元組中選一個] |
[...] |
匹配字元組中的字元 |
[^...] |
匹配除了字元組內所有內容,之外的所有字元 |
字元組內容 |
待匹配字元 |
匹配結果 |
說明 |
[0123456789] |
8 |
True |
字元組裡列舉的各種字元,必須滿足一個,否則返回假,不匹配 |
[abcdefg] |
9 |
False |
由於字元組中沒有"9"字元,所以不匹配 |
[0-9] |
7 |
True |
可用 - 表示範圍,[0-9] 和 [0123456789]是一個意思 |
[a-z] |
s |
True |
[a-z]匹配所有的小寫字母 |
[A-Z] |
B |
True |
[A-Z]就表示所有的大寫字母 |
[0-9a-fA-F] |
e |
True |
可以匹配數字,大小寫形式的a-f. 該正則可驗證十六進位制 |
print(re.findall('a[abc]b','aab abb acb adb')) # aab abb acb
print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb')) # a1b a2b a3b
# 最佳化寫法 0123456789 => 0-9
print(re.findall('a[0-9]b','a1b a2b a3b acb ayb')) # a1b a2b a3b
print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) # acb adb
# 最佳化寫法 abcdefg => a-g 表達所有的小寫字母 a-z
print(re.findall('a[a-g]b','a1b a2b a3b acb ayb adb')) # acb adb
print(re.findall('a[ABCDEFG]b','a1b a2b a3b aAb aDb aYb')) # aAb aDb
# 最佳化寫法 ABCDEFG => A-G 表達所有的大寫字母 A-Z
print(re.findall('a[A-G]b','a1b a2b a3b aAb aDb aYb')) # aAb aDb
print(re.findall('a[A-Z]b','a1b a2b a3b aAb aDb aYb')) # aAb aDb aYb
# 注意點: 不能直接寫A-z 中間ascii編碼中包含了特殊的符號
print(re.findall('a[A-z]b','a1b a2b a3b acb ayb adb a[b'))
# 匹配所有的字母和數字
print(re.findall('a[a-zA-Z0-9]b','a1b a2b a3b acb ayb adb a[b'))
# out ['a1b', 'a2b', 'a3b', 'acb', 'ayb', 'adb']
print(re.findall('a[0-9a-zA-Z]b','a-b aab aAb aWb aqba1b')) #aab aAb aWb aqb a1b
print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) # a1/b
# ^ 在字元組開頭的位置出現代表 除了...的意思
print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) #a%b a&b
# 匹配^-\等特殊字元時 ,需要前面加上\進行轉義
strvar = "a^c a-c a\c"
lst = re.findall(r"a[\^\-\\]c",strvar)
print(lst) # ['a^c', 'a-c', 'a\\c'] 非隱式轉義
print(lst[-1]) # a\c 轉義了
# 注意點:為了防止轉義,在正規表示式中或者要匹配的字串中,無腦加r實現匹配
strvar = r"a\b"
lst = re.findall(r"a\\b",strvar)
print(lst[0])
量詞
量詞 |
用法說明 |
? |
重複0次或1次 |
+ |
重複1次或多次 (至少1次) |
* |
重複0次或多次 (任意次) |
|
重複n次 |
|
重複n次或更多次 (至少n次) |
|
重複n到m次 |
.* .+ |
貪婪模式匹配 最深度原則 |
.*? .+? |
非貪婪模式匹配 |
import re
'''1) ? 匹配0個或者1個a '''
print(re.findall('a?b','abbzab abb aab')) # ab b ab ab b ab
'''2) + 匹配1個或者多個a '''
print(re.findall('a+b','b ab aaaaaab abb')) # ab aaaaaab ab
'''3) * 匹配0個或者多個a '''
print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b
'''4) {m,n} 匹配m個至n個a '''
# 1 <= a <= 3
print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) #aaab ab aab ab aab
# {2} 代表必須匹配2個a
print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab
# {2,} 代表至少匹配2個a
print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab
貪婪演算法和非貪婪演算法
"""
匹配符+量詞
"""
strvar = "劉能和劉老根和劉羅鍋111子222子"
"""
.只匹配一個字元
"""
lst = re.findall("劉.",strvar)
print(lst) # lst = re.findall("劉.?",strvar)
lst = re.findall("劉.?",strvar)
print(lst) # lst = re.findall("劉.?",strvar)
# out ['劉能', '劉老', '劉羅']
strvar = "劉能和劉老根和劉羅鍋111子222子"
lst = re.findall("劉.+",strvar)
print(lst) # ['劉能和劉老根和劉羅鍋111子222子']
lst = re.findall("劉.*",strvar)
print(lst) # ['劉能和劉老根和劉羅鍋111子222子']
lst = re.findall("劉.{1,20}",strvar)
print(lst) # ['劉能和劉老根和劉羅鍋111子222子']
lst = re.findall("劉.*子",strvar)
print(lst)
# out ['劉能和劉老根和劉羅鍋111子222子'] 優先匹配量詞最多
# 非貪婪匹配(模式)
lst = re.findall("劉.??",strvar)
print(lst) # ['劉', '劉', '劉']
lst = re.findall("劉.+?",strvar)
print(lst) # 劉能 劉老 劉羅
lst = re.findall("劉.*?",strvar)
print(lst) # ['劉', '劉', '劉']
lst = re.findall("劉.{1,20}?",strvar)
print(lst) # ['劉能', '劉老', '劉羅']
lst = re.findall("劉.*?子",strvar)
print(lst) # 劉能和劉老根和劉羅鍋111子 非貪婪匹配
邊界符
邊界符 |
說明 |
\b |
匹配一個字元的邊界 |
^ |
匹配字串的開始 |
$ |
匹配字串的結尾 |
"word"
"""
卡主左邊界:\bw
卡主右邊界:d\b
"""
strvar = "word old fuck"
# 右邊界
lst = re.findall(r"d\b",strvar) # ['d', 'd']
lst = re.findall(r".*d\b",strvar) # ['word old']
lst = re.findall(r".*?d\b",strvar) # ['word' 'old']
print(lst)
# 左邊界
lst = re.findall(r"\bw",strvar)
print(lst) # ['w']
lst = re.findall(r"\bw.*",strvar)
print(lst) # ['word old fuck']
lst = re.findall(r"\bw.*?",strvar)
print(lst) # ['w']
lst = re.findall(r"\bw.*? ",strvar)
print(lst) # ['word ']
# 空格在正規表示式中,不能隨意加,是參與匹配的.
lst = re.findall(r"\bw\S*",strvar)
print(lst) # ['word'] # 貪婪匹配
# (4) ^ $的使用
"""
^ 寫在在字串的開頭,表達必須以某個字元開頭
$ 寫在在字串的結尾,表達必須以某個字元結尾
當使用了^ $ 代表要把該字串看成一個整體
"""
strvar = "大哥大嫂大爺"
print(re.findall('大.',strvar)) # ['大哥', '大嫂', '大爺']
print(re.findall('^大.',strvar)) # ['大哥']
print(re.findall('大.$',strvar)) # ['大爺']
print(re.findall('^大.$',strvar))# []
print(re.findall('^大.*?$',strvar)) # ['大哥大嫂大爺']
print(re.findall('^大.*?大$',strvar)) # []
print(re.findall('^大.*?爺$',strvar)) # ['大哥大嫂大爺']
print(re.findall('^g.*? ' , 'giveme 1gfive gay')) # giveme
print(re.findall('five$' , 'aassfive')) # [five]
print(re.findall('^giveme$' , 'giveme')) # ['giveme']
print(re.findall('^giveme$' , 'giveme giveme')) # []
print(re.findall('giveme' , 'giveme giveme')) # ['giveme', 'giveme']
print(re.findall("^g.*e",'giveme 1gfive gay')) # ['giveme 1gfive']
分組字元
分組 |
用法說明 |
a|b |
匹配字元a 或 字元b (如果兩個當中有重合部分,把更長的那個放前面) |
(ab) |
匹配括號內的表示式 ,將()作為一個分組 |
\num |
引用分組num匹配到的字串 |
(?P) |
給分組命名 |
(?P=name) |
引用別名: 把name分組所匹配到的內容引用到這裡 |
import re
# (1)分組
print(re.findall('.*?_good','wusir_good alex_good secret男_good'))
# ['wusir_good', ' alex_good', ' secret男_good']
print(re.findall('(.*?)_good','wusir_good alex_good secret男_good'))
# ['wusir', ' alex', ' secret男']
# (?:) 代表不優先顯示分組裡面的內容,只是顯示正常匹配到的內容
print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))
# (2) | 代表或 , a|b 匹配字元a 或者 匹配字元b .
import re
strvar = "abceab"
lst = re.findall("a|b",strvar)
print(lst) #['a', 'b', 'a', 'b']
# 注意點:把不容易匹配到的內容放到前面,把容易匹配到的內容放到後面
strvar = "abcdeabc234f"
lst = re.findall("abcd|abc",strvar)
print(lst) #['abcd', 'abc']
# 匹配小數
strvar = "3.... ....4 .3 ...3 1.3 9.89 10"
lst = re.findall(r"\d+\.\d+",strvar)
print(lst)
# 匹配小數和整數
lst = re.findall(r"\d+\.\d+|\d+",strvar)
print(lst)
# 使用分組改造
'''findall優先顯示括號裡的內容,需要加上?:取消哦優先顯示,按照匹配到的內容顯示'''
lst = re.findall(r"\d+(?:\.\d+)?",strvar)
print(lst)
# 匹配135或171的手機號
strvar = "13566668888 17366669999 17135178392"
lst = re.findall(r"(?:135|171)\d{8}",strvar)
print(lst)
# 最佳化,只能匹配出一個手機號
strvar = "13566668888"
lst = re.findall(r"^(?:135|171)\d{8}$",strvar) # 卡住左右邊界
print(lst)
strvar = "13566668888"
obj = re.search(r"^(135|171)\d{8}$",strvar)
print(obj) # <re.Match object; span=(0, 11), match='13566668888'>
print(obj.group()) # 13566668888
print(obj.groups()) # ('135',) 顯示括號優先匹配的