Python常用模組——re模組
有些人在面臨問題的時候會想:“我知道,我將使用正則表示式來解決這個問題。”這讓他們面臨的問題變成了兩個。
—— Jamie Zawinski
首先我們對比一下兩段程式碼處理使用者輸入手機號的不同
1 phone_num = input('請輸入手機號:') 2 if len(phone_num) == 11 \ 3 and phone_num.isdigit()\ 4 and phone_num[:3] in ['130','131','132']: 5 print程式碼1('hello') 6 else:print('非聯通號!')
1 import re 2 phone_num = input('請輸入手機號:') 3 if re.findall('^(130|131|132)[0-9]{8}$',phone_num): 4 print('hello') 5 else:print('非聯通號!')程式碼2
對比來看程式碼1比較通俗易懂,程式碼2看起來有些不太容易理解但是可以使得程式碼更加的簡潔
1.正則表示式
re模組提供了對正則表示式的支援,學習re模組之前要了解正則表示式:
正則表示式其實是匹配文字片段的模式,最簡單的正則表示式是普通的字串,與自己匹配,可以使用這種匹配行為來完成一下工作:在文字中查詢模式,將特定的模式替換為計算得到的值,以及將文字分割為片段。
正則表示式線上測試工具 http://tool.chinaz.com/regex/
1.1萬用字元
. | 匹配除換行符以外的任意字元 |
\w | 匹配字母或數字或下劃線 |
\s | 匹配任意的空白符 |
\d | 匹配數字 |
\n | 匹配一個換行符 |
\t | 匹配一個製表符 |
\b | 匹配一個單詞的結尾 |
^ | 匹配字串的開始 |
$ | 匹配字串的結束 |
\W | 匹配非字母或數字或下劃線 |
\D | 匹配非數字 |
\S | 匹配非空白符 |
a|b | 匹配字元a或字元b |
() | 匹配括號內的表示式,也表示一個組 |
[...] | 匹配字符集中的字元 |
[^...] | 匹配除了字符集中的字元 |
1.2字符集
用方括號將一個子串括起來,建立一個所謂的字符集
例如"[a-zA-Z0-9]"與大小寫字母以及數字都匹配,但需要注意的是字符集只能匹配一個字元
要排除字元就可以在開頭加上^字元,例如"[^abc]"與除a、b和c外的其他任何字元都匹配
字符集 | 匹配字元 | 結果 | 說明 |
[0123456789] | 1 | True | 在一個字元組裡列舉合法的所有字元,字元組裡的任意一個字元 |
[0-9] | 1 | True | 也可以用-表示範圍,[0-9]就和[0123456789]是一個意思 |
[a-z] | a | True | 同樣的如果要匹配所有的小寫字母,直接用[a-z]就可以表示 |
[A-Z] | A | True | [A-Z]就表示所有的大寫字母 |
1.3量詞
* | 重複零次或更多次 |
+ | 重複一次或更多次 |
? | 重複零次或一次 |
{n} | 重複n次 |
{n,} | 重複n次或更多次 |
{n,m} | 重複n到m次 |
1.4分組 ()與 或 |[^]
匹配身份證號為15或18位字串組成,15位為純數字,首位不能為零。
正則 | 待匹配字元 | 匹配結果 | 說明 |
^[1-9]\d{13,16}[0-9x]$ | 53010219200508011x | 53010219200508011x | 雖可匹配但存在問題 |
^[1-9]\d{14}(\d{2}[0-9x]$)? | 53010219200508011x | 53010219200508011x | 括號內為子模式,子模式後加量詞 |
([1-9]\d{16}[0-9x]|[1-9]\d{14}) | 53010219200508011x | 53010219200508011x | 括號內加"|",變為二選一模式,先匹配前面後匹配後面 |
1.5 特殊字元進行轉義
普通字元與自己匹配,但特殊字元情況不同,要讓特殊字元與普通字元一樣就要對其進行轉義:在正則前加"\"
請注意,為表示模式re要求的單個反斜槓,需要在字串中寫兩個反斜槓,讓直譯器對其轉義,包含兩層含義,直譯器執行的轉義和模組re進行的轉義
當然可以使用原始字串,如r'\d'
>>> import re
>>> print(re.findall('\\\\d', '\\d')) # 匹配字元"\d"時,正則表達為"\\d",然後Python還要對其中兩個斜槓在進行轉義,最終規則表示式為"\\\\d"
['\\d']
>>> print(re.findall(r'\\d',r'\d')) # 使用原始字串省去不必要的麻煩
['\\d']
1.6 貪婪和非貪婪匹配
貪婪匹配:在滿足匹配時,匹配儘可能長的字串,預設情況下,採用貪婪匹配
加上"?"變為非貪婪匹配
*? 重複任意次,但儘可能少重複 +? 重複1次或更多次,但儘可能少重複 ?? 重複0次或1次,但儘可能少重複 {n,m}? 重複n到m次,但儘可能少重複 {n,}? 重複n次以上,但儘可能少重複
一般這樣使用時要加上結尾條件,否則只會匹配量詞的最少重複次數
你.*? | 你好嗎 | 你 |
你.*?嗎 | 你好嗎你真的好嗎 | 你好嗎 |
2.模組re的常用函式
函式 | 描述 |
compile(pattern, flags=0) | 根據包含正則表示式的字串建立模式物件 |
escape(string) | 對字串中的所有正則表示式的特殊字元進行轉義 |
findall(pattern, string, flags=0) | 返回一個列表,其中包含字串中的所有與正則模式匹配的子串 |
search(pattern, string, flags=0) | 在字串中查詢模式 |
split(pattern, string, maxsplit=0, flags=0) | 根據模式來分割字串 |
sub(pattern, repl, string, count=0, flags=0) | 將字串中與模式匹配的子串替換為 repl |
match(pattern, string, flags=0) | 在字串開頭查詢模式 |
subn(pattern, repl, string, count=0, flags=0) | 將字串中與模式匹配的子串替換為 repl,返回元組,元組包含替換後結果和替換次數 |
finditer(pattern, string, flags=0) | 返回一個包含結果的迭代器 |
print(re.findall('你','你好你是')) # ['你', '你'] ret = re.search('你','好是') # 找到後需要呼叫group()方法,找不到返回None,None不能呼叫group()方法 if ret: print(ret.group()) ret = re.match('你','ni好你是') # 和search用法類似 if ret: print(ret.group()) ret = re.split('b','abc') # 按“b”分割字串 print(ret) # ['a', 'c'] ret = re.split('[ad]','adbcde') # 先按“a”分割,再按“b”分割 print(ret) print(re.sub('\d','$','zhao123')) print(re.subn('\d','$','zhao123')) obj = re.compile('你好') ret = obj.findall('你好嗎') print(ret) ret = re.finditer('你好','你好嗎你好') print(ret.__next__().group())