re正則表示式
引子
請從以下檔案裡取出所有的手機號
姓名 地區 身高 體重 電話 況詠蜜 北京 171 48 13651054608 王心顏 上海 169 46 13813234424 馬纖羽 深圳 173 50 13744234523 喬亦菲 廣州 172 52 15823423525 羅夢竹 北京 175 49 18623423421 劉諾涵 北京 170 48 18623423765 嶽妮妮 深圳 177 54 18835324553 賀婉萱 深圳 174 52 18933434452 葉梓萱 上海 171 49 18042432324 杜姍姍 北京 167 49 13324523342
你能想到的辦法是什麼?
必然是下面這種吧?
f = open("兼職白領學生空姐模特護士聯絡方式.txt",'r',encoding="gbk")
phones = []
for line in f:
name,city,height,weight,phone = line.split()
if phone.startswith('1') and len(phone) == 11:
phones.append(phone)
print(phones)
有沒有更簡單的方式?
手機號是有規則的,都是數字且是11位,再嚴格點,就都是1開頭,如果能把這樣的規則寫成程式碼,直接拿規則程式碼匹配檔案內容不就行了?
這麼nb的玩法是什麼?它的名字叫正則表示式!
re模組
正則表示式就是字串的匹配規則,在多數程式語言裡都有相應的支援,python裡對應的模組是re
常用的表示式規則
'.' 預設匹配除\n之外的任意一個字元,若指定flag DOTALL,則匹配任意字元,包括換行 '^' 匹配字元開頭,若指定flags MULTILINE,這種也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE) '$' 匹配字元結尾, 若指定flags MULTILINE ,re.search('foo.$','foo1\nfoo2\n',re.MULTILINE).group() 會匹配到foo1 '*' 匹配*號前的字元0次或多次, re.search('a*','aaaabac') 結果'aaaa' '+' 匹配前一個字元1次或多次,re.findall("ab+","ab+cd+abb+bba") 結果['ab', 'abb'] '?' 匹配前一個字元1次或0次 ,re.search('b?','alex').group() 匹配b 0次 '{m}' 匹配前一個字元m次 ,re.search('b{3}','alexbbbs').group() 匹配到'bbb' '{n,m}' 匹配前一個字元n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 結果'abb', 'ab', 'abb'] '|' 匹配|左或|右的字元,re.search("abc|ABC","ABCBabcCD").group() 結果'ABC' '(...)' 分組匹配, re.search("(abc){2}a(123|45)", "abcabca456c").group() 結果為'abcabca45' '\A' 只從字元開頭匹配,re.search("\Aabc","alexabc") 是匹配不到的,相當於re.match('abc',"alexabc") 或^ '\Z' 匹配字元結尾,同$ '\d' 匹配數字0-9 '\D' 匹配非數字 '\w' 匹配[A-Za-z0-9] '\W' 匹配非[A-Za-z0-9] 's' 匹配空白字元、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 結果 '\t' '(?P...)' 分組匹配 re.search("(?P[0-9]{4})(?P[0-9]{2})(?P[0-9]{4}
re的匹配語法有以下幾種
-
re.match 從頭開始匹配
-
re.search 匹配包含
-
re.findall 把所有匹配到的字元放到以列表中的元素返回
-
re.split 以匹配到的字元當做列表分隔符
-
re.sub 匹配字元並替換
-
re.fullmatch 全部匹配
re.compile(pattern, flags=0)
Compile a regular expression pattern into a regular expression object, which can be used for matching using its match(), search() and other methods, described below.
The sequence
prog = re.compile(pattern)
result = prog.match(string)
is equivalent to
result = re.match(pattern, string)
but using re.compile() and saving the resulting regular expression object for reuse is more efficient when the expression will be used several times in a single program.
re.match(pattern, string, flags=0)
從起始位置開始根據模型去字串中匹配指定內容,匹配單個
-
pattern 正則表示式
-
string 要匹配的字串
-
flags 標誌位,用於控制正則表示式的匹配方式
import re
obj = re.match('\d+', '123uuasf') #如果能匹配到就返回一個可呼叫的物件,否則返回None
if obj:
print obj.group()
Flags標誌符
-
re.I(re.IGNORECASE): 忽略大小寫(括號內是完整寫法,下同)
-
re.M(MULTILINE): 多行模式,改變’^’和’$’的行為
-
re.S(DOTALL): 改變’.’的行為,make the ‘.’ special character match any character at all, including a newline; without this flag, ‘.’ will match anything except a newline.
-
re.X(re.VERBOSE) 可以給你的表示式寫註釋,使其更可讀,下面這2個意思一樣
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""",
re.X)
b = re.compile(r"\d+\.\d*")
re.search(pattern, string, flags=0)
根據模型去字串中匹配指定內容,匹配單個
import re
obj = re.search('\d+', 'u123uu888asf')
if obj:
print obj.group()
re.findall(pattern, string, flags=0)
match and search均用於匹配單值,即:只能匹配字串中的一個,如果想要匹配到字串中所有符合條件的元素,則需要使用 findall。
import re
obj = re.findall('\d+', 'fa123uu888asf')
print obj
re.sub(pattern, repl, string, count=0, flags=0)
用於替換匹配的字串,比str.replace功能更加強大
>>>re.sub('[a-z]+','sb','武配齊是abc123',)
>>> re.sub('\d+','|', 'alex22wupeiqi33oldboy55',count=2)
'alex|wupeiqi|oldboy55'
re.split(pattern, string, maxsplit=0, flags=0)
用匹配到的值做為分割點,把值分割成列表
>>>s='9-2*5/3+7/3*99/4*2998+10*568/14'
>>>re.split('[\*\-\/\+]',s)
['9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14']
>>> re.split('[\*\-\/\+]',s,3)
['9', '2', '5', '3+7/3*99/4*2998+10*568/14']
re.fullmatch(pattern, string, flags=0)
整個字串匹配成功就返回re object, 否則返回None
re.fullmatch('\w+@\w+\.(com|cn|edu)',"[email protected]")