正則re

江寒雨發表於2024-03-10

正規表示式

它是約束字串匹配某種形式的規則

正規表示式有什麼用?

1.檢測某個字串是否符合規則.比如:判斷手機號,身份證號是否合法
2.提取網頁字串中想要的資料.比如:爬蟲中,提取網站天氣,資訊,股票程式碼,星座運勢等具體關鍵字

線上測試工具 http://tool.chinaz.com/regex/

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',) 顯示括號優先匹配的

相關文章