Python的正則表達(dá)式的模塊是re灌灾,它的基本語(yǔ)法的規(guī)則就是指定一個(gè)字符序列,比如:
>>>import re
>>>s='123abc456abce789'
>>>re.findall(r'abc',s)? ? ? #在s字符串里找到所有的abc卖哎,并把他們放到列表list里
以上運(yùn)行結(jié)果就是:['abc','abc']
re規(guī)定了若干語(yǔ)法規(guī)則:
1)功能字符:'.'? ? '*'? '+'? '|'? '?'? '^'? '$'? '\' 等。
? ? '/':? 轉(zhuǎn)義引導(dǎo)符號(hào)架曹。
2)規(guī)則分界符:'['? ']'? '('? ')'? '{' '}'等幾種特殊括號(hào)
3)預(yù)定義轉(zhuǎn)義字符集:‘\d’? '\w'? '\s'等等诱鞠,他們是以字符 '\'開頭,后面接一個(gè)特定的字符形式奢入,用來(lái)指示一個(gè)預(yù)定姓迅。
4)其他特殊功能字符:'#'? '!'? ':'? '-' 等,他們只在特定的情況下表示特殊的含義俊马,比如? (?#...)? 就表示一個(gè)注釋,里面的內(nèi)容會(huì)被忽略掉肩杈。
1.0 通配符
'.'? 匹配1個(gè)任意字符(但不包括換行符\n)
'\d' 匹配1個(gè)數(shù)字柴我,等價(jià)于[0-9]
'\D' 是'\d'的反義詞,等價(jià)于[^0-9]
'\w' 匹配1個(gè)字母或數(shù)字扩然,等價(jià)于 '[a-zA-Z0-9]'
'\W' 是'\w' 的反義詞艘儒,等價(jià)于'[^a-zA-Z0-9]'
'\s' 匹配一個(gè)空白符,等價(jià)于'[ \t\n\r\v\f](注意含空格)夫偶;
1.1? '[? ]' 表示集合
1)? '-' 用在字母或者數(shù)字之間表示一個(gè)區(qū)間界睁,如下:
'[a-z]'? 表示匹配所有的小寫英文字母'[A-Z]'? 表示匹配所有的大寫英文字母
'[a-zA-Z]'? 表示匹配所有的大小寫英文字母
'[0-9]'? ? 表示匹配0-9的所有數(shù)字
ps:'[z-a]' 寫法錯(cuò)誤,順序不能顛倒
2)'^'? 在開頭表示“非”兵拢,其他位置則表示他本身翻斟,如下:
'[^a-zA-Z]'? 表示不匹配所有英文字母
'[a-z^A-Z]'? ? 表示匹配所有英文字母和字符 '^'
3)'|'? 表示“或”,將兩個(gè)規(guī)則并列起來(lái)说铃,匹配其中之一就可以了访惜,如:
'[a-zA-Z]|[0-9]' 相當(dāng)于 '[a-zA-Z0-9]'? 表示匹配所有的字母和數(shù)字
1.2? 重復(fù)
'*'? 0或多次匹配(前面的規(guī)則)
'+'? 1次或多次匹配? ? (至少一次,可以多次匹配)>=1
'?'? 0或1次匹配? ? (只匹配前面的規(guī)則0次或1次)
例1:匹配以下字符串中的前一部分是字母腻扇,后一部分是數(shù)字或是沒有變量的名字债热。
>>>s='aaa bbb111 cc22cc 33dd'
>>>re.finall(r'\b[a-z]+\d*\b',s)
? ? ? ['aaa','bbb111']?
#匹配至少一個(gè)字母開頭([a-z]+),以連續(xù)數(shù)字結(jié)尾或沒有數(shù)字(\d*)
>>>re.findall(r'[a-z]'+\d*',s]
['aaa','bbb111','cc22','cc','dd']?
#與上面相比幼苛,無(wú)'\b'邊界窒篱,會(huì)把單詞給拆開
例2:匹配一個(gè)數(shù)字,這個(gè)數(shù)字可以是一個(gè)整數(shù),也可以是一個(gè)科學(xué)計(jì)數(shù)法記錄的數(shù)字墙杯,比如123和10e3都是正確的數(shù)字配并。
>>>s='123 10e3 20e4e4 30ee5'
>>>re.findall(r'\b\d+[eE]?\d*\b',s)?
? ['123','10e3']
#'\b\d+[eE]?\d*\b'拆開來(lái)看就是:'\b'前后都有邊界 ,開頭'\d+' (至少一個(gè)數(shù)字)霍转, 然后'[eE]?' (沒有或1個(gè)e荐绝、E ), 結(jié)尾'\d*'(沒有或者多個(gè)數(shù)字)避消;
1.3精確匹配和最小匹配? '{? }'
1.3.1精確匹配規(guī)則如下:
'{m}'? 精確匹配m次 低滩,如: '{3}''{m,n}'? 匹配最少m次,最多n次 (m<n)岩喷,如: '{3,5}'
'{m,}'? ? 只匹配最少m次 恕沫,如: '{3,}'
'{,n}'? 只匹配最多n次,如: '{,5}'
例:尋找下面的字符串
? ? ? a:3位數(shù)
? ? b:2位數(shù)到4位數(shù)
? ? c:5位數(shù)以上數(shù)
? ? d:4位數(shù)以下的數(shù)
>>>s='1 22 333 4444 55555 666666'
>>>re.findall(r'\b\d{3}\b',s)? ? #a:3位數(shù)
['333']
>>>re.findall(r'\b\d{2,4}\b',s)? # b:2位數(shù)到4位數(shù)
['22','333','4444']
>>>re.findall(r'\b\d{5,}\b',s)? # c:5位數(shù)以上數(shù)
['55555','666666']
>>>re.findall(r'\b\d{,4}\b',s)? # d:4位數(shù)以下的數(shù)
['1','22','333','4444']
1.3.2? '*?'? '+?'? '??' 最小匹配
s=r'/*part1*/code/*part2*/'? ? #此為一個(gè)c語(yǔ)言的注釋
#如果使用最大規(guī)則:
>>>re.findall(r'/\*.*\*/',s)
['/*part1*/code/*part2*/']? ? #結(jié)果把整個(gè)字符串都寫進(jìn)去了
>>>re.findall(r'/\*.*?*\*/',s)? ? #'*?'表示盡可能少的匹配
['/*part1*/','/*part2*/']?
#ps:'/\*.*?*\*/'纱意,其中'/\*'是匹配'*'本身婶溯,'.'表示匹配除換行符'\n'外的所有字符,'.*'表示匹配0或多次換行符'\n'外的所有字符偷霉,而'.*迄委?'表示匹配盡可能少的匹配0或多次換行符'\n'外的所有字符,就是part1和part2部分类少。
1.4? 其他規(guī)則
>>>s='123\n456\n789'
>>>re.findall(r'.+',s)? #至少1次('+')匹配除換行符\n外的所有字符
['123','456','789']
>>>re.findall(r'.+',s,re.S)? #加上大寫的S叙身,則匹配含\n的所有字符
['123\n456\n789']
>>>s='12 34\n56 78\n90'
>>>re.findall(r'^\d+',s,re.M)? ? #至少1次('+')匹配位于行首('^')的數(shù)字(\d')
['12','56','90']
>>>re.findall(r'\d+$',s,re.M)? ? #至少1次('+')匹配位于行尾('$')的數(shù)字(\d')
['34','78','90']
>>>re.findall(r'\A\d+',s,re.M)? ? #至少1次('+')匹配位于字符串開頭('\A')的數(shù)字(\d')
['12']
>>>re.findall(r'\d+\Z',s,re.M)? ? #至少1次('+')匹配位于字符串最后('\Z')的數(shù)字(\d')
['90']
>>>s='abc abcde bc bcd'
'\b'? 匹配單詞邊界
>>>re.findall(r'\bbc\b',s)
['bc']? ? ? ? #匹配一個(gè)獨(dú)立的單詞'bc',而當(dāng)它是其他單詞的一部分的時(shí)候硫狞,不匹配
'\B'? 匹配非邊界
>>>re.findall(r'\Bbc\W+',s)? ? #匹配包含'bc'但不以‘bc’開頭,并且后面至少有一個(gè)字母或數(shù)字的單詞
['bcde']? ? #成功匹配了'abcde'中的'bcde',而沒有匹配'bcd'
>>>re.findall(r'\sbc\s',s)? #匹配一個(gè)獨(dú)立的單詞bc
[' bc ']? ? #不過輸出的bc前后會(huì)有空格
'(?:)' 無(wú)捕獲組
例:匹配字符串中重復(fù)的'ab'
>>>s='ababab abbabb aabaab'
>>>re.findall(r'\b(?:ab)+\b',s)
['ababab']
>>>re.findall(r'\b(ab)+\b',s)? #只用一個(gè)括號(hào)信轿,就相當(dāng)于一個(gè)組(grou)
['ab']? ? #ps:關(guān)于組后面會(huì)詳細(xì)介紹
'(?#)'? 注釋
python允許你在正則表達(dá)式中注釋,在'(?#'和')'中的內(nèi)容將會(huì)被忽略
2.界定
'(?<=...)'? 前向界定
'(?=...)'? ? 后向界定
ps:括號(hào)中的'...'代表你希望匹配的字符串的前面残吩、后面應(yīng)該出現(xiàn)的字符串
例:你希望找出C語(yǔ)言注釋中的內(nèi)容财忽,他們是否包含在'/*'和'*/'之間,不過你并不希望匹配的結(jié)果把'/*'和'*/'也包括進(jìn)來(lái)泣侮,那么你可以這樣用即彪。
>>>s=r'/*comment1*/code/*comment2*/'
>>>re.findall(r'(?<=/\*).+?(?=\*/)',s)? #匹配字符前面是'/*'后面是'*/'的字符
['comment1','comment2']
ps:前向界定的表達(dá)式必須是常值,不過可以在后向界定寫正則旁瘫,如下所示:
>>>s='aaa111aaa,bbb222,333ccc'
>>>re.findall(r'(?<=[a-z]+)\d+(?=[a-z]+)',s)? ? #此用法錯(cuò)誤,前向界定里不能用正則
error:look-behind requires fixed-width pattern.? ? #結(jié)果報(bào)錯(cuò)了
>>>re.findall(r'\d+(?=[a-z]+)',s)? #后面的界定可以用正則
['111','333']? ? #界定是包含在結(jié)果中的
ps:如果你一定要匹配夾在字母中間的數(shù)字祖凫,你可以使用組(group)的方式,如:
>>>re.findall(r'[a-z]+(\d+)[a-z]+',s)? #規(guī)則內(nèi)酬凳,組以外的會(huì)被忽略
['111']
'(?<!...)'? 前向非界定? #只有當(dāng)你希望的字符串前面不是'...'的內(nèi)容才匹配
'(?!...)'? 后向非界定? ? #只有當(dāng)你希望的字符串后不跟著'...'的內(nèi)容才匹配
s='aaa111aaa,bbb222,333ccc'
>>>re.findall(r'\d+(?![a-z]+)',s)
['11','222','333']
>>>re.findall(r'\d+(?!\w+)',s)? #匹配數(shù)字后面不跟著字母或者數(shù)字
['222']
3.組的基本知識(shí)
1) '('? ')'? 無(wú)命名組
>>>s='aaa111aaa,bbb222,333ccc'
>>>re.findall(r'[a-z]+(\d+)[a-z]+',s)? ? #一個(gè)組
['111']? #只返回了匹配包含在'( )'里的
>>>s='aaa111aaa,bbb222,333ccc,444ddd444,555eee666,fff777ggg'
>>>re.findall(r'([a-z]+)\d+([a-z)+',s)? #有兩個(gè)組惠况,找出中間夾有數(shù)字的字母
[('aaa','aaa'),('fff','ggg')]?
>>>re.findall(r'[a-z]+(/d+)([a-z]+)',s)
[('111','aaa'),('777','ggg')]? ? #有組的話,組以外的不返回
2) '(?p=name)'調(diào)用已匹配的命名組
ps:就是組命名宁仔,然后下次要使用相同的規(guī)則的組時(shí)候可以直接調(diào)用稠屠,如
>>>re.findall(r'(?p<gl>[a-z]+)\d(?p=gl)'? #找出被中間夾有數(shù)字的前后同樣的字母
['aaa']
3)'\number' 通號(hào)調(diào)用已匹配的組
>>>re.findall(r'([a-z]+)\d+\1',s)? #找出被中間夾有數(shù)字的前后同樣的字母
['aaa']
>>>s='111aaa222aaa111,333bbb444bb33'
>>>re.findall(r'(\d+)([a-z]+)(\d+)(\2)(\1)',s)? #找出完全對(duì)稱的‘?dāng)?shù)字-字母-數(shù)字-字母-數(shù)字’
[('111','aaa','222','aaa','111')]? #注意'\number'與'(\number)'的區(qū)別,以及命名組調(diào)用的區(qū)別
4)'(?(id/name)yes-pattern}|no-pattern)'? 判斷指定組是否已匹配,執(zhí)行相應(yīng)的規(guī)則
>>>s='< usr1@mail1 > ursl2@mail2'
>>>re.findall(r'(<)?\s*(\w+@\w+)\s*(?(1)>)',s)
[('<','usr1@mail1'),('','ursl2@mail2')]