Python常用正則表示式語法和寫法
今天因為看一個爬蟲的例子,看到資料抓取的時候別人用的正則表示式去匹配想要的資料.當即對這個表示式感興趣起來,仔細閱讀了一下相關文件,對其有了大概的認識,索性寫了一篇文章來介紹python中相關正則表示式的用法,以便自己日後參閱!
相關介紹
正則表示式是一種高度精度化的語言,我們可以用一段特定字串生成的正則來過濾,替換,查詢我們需要的資料.正則表示式在執行的的時候會被編譯成一系列的碼,並由C編寫的匹配引擎執行,一般來說效率比一般的演算法效率更高,但是卻更不易於理解.大家也可以參考官方文件.
相關的庫
Python的正則相關庫用的最多的是RE模組了,因為是python的內建模組,我們只需要直接匯入re模組即可使用其功能.
re模組常用函式用法
下面要介紹的相關函式非常重要,我們需要詳細講解一下!
1.compile 函式
re.compile(pattern, flags=0)
compile函式類似一個正則工廠,他返回的是一個正則表示式的模式物件,我們可以用這個物件去加工任何需要加工的字串.第一個引數傳入的是正則的表示式字串,第二個引數傳遞的是匹配的模式.
2.match 函式
pattern=re.compile('正則字串')
pattern.match('要匹配的字串')
match函式是一個匹配函式,我們用compile函式生成的工廠物件,對要加工的字串進行匹配,如果有響應的字串,就會返回,否者返回None.需要注意的是,match函式匹配字串是從字串開頭匹配的,假如開頭沒有找到,就不會繼續找下去!而且他只會返回最先匹配到的字串,也就是說,假如可能一個字串中有兩個可以匹配的地方,他只會返回最先匹配到的那部分!
舉個例子:
pattm=re.compile('a') #a為正則字串
pstr=pattm.match('aabcad') #abcd是要匹配的字串
if pstr!=None:
print(pstr.group())
else:
print('無匹配!')
>>> a #執行結果為a ,注意這個a是第一個a!
由於’adcd’字串中第一位有我們需要匹配的正則字元a,所以成功匹配到了a!
pattm=re.compile('b') #a為正則字串 pstr=pattm.match('abcd') #abcd是要匹配的字串 if pstr!=None: print(pstr.group()) #這裡group函式下面會說 else: print('無匹配!') >>> 無匹配! #執行沒有匹配到
上面我們改了一下正則規則為b,就是說匹配的字串第一個字元必須為b,否者匹配不成功!
3.search 函式
pattern=re.compile('正則字串')
pattern.search('要匹配的字串')
search 函式和match函式有個相同點就是,他只會返回最先匹配到那部分字串!但是他和match不用的是,他不會只侷限於在字串的開頭查詢,他會查詢整個字串,直到找到匹配的部分為止!
pattm=re.compile('a')
pstr=pattm.search('baabcad')
if pstr!=None:
print(pstr.group())
else:
print('無匹配!')
>>>> a #結果為a,這裡的a是字串出現的第一個a
假如字串中沒有匹配的字元,返回None
pattm=re.compile('f')
pstr=pattm.search('baabcad')
if pstr!=None:
print(pstr.group())
else:
print('無匹配!')
>>> 無匹配! #字串中沒有匹配到f字元!
3.findAll 函式
findAll函式不但會查詢整個字串,並且會將匹配到的所有字元返回!而不僅限於返回第一個匹配到的!他會將返回的所有字元裝載到一個列表物件返回.
pattm=re.compile('a')
pstr=pattm.findall('baabcad')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>>> ['a', 'a', 'a'] #返回了所有匹配到的a
同樣,假如沒有匹配到,會返回一個空列表物件
4.split函式
分割函式,類似於字串分割.會根據正則字元為基準分割我們需要的字串.
pattm=re.compile(':')
pstr=pattm.split('baa:bcad')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['baa', 'bcad'] #根據:分割成了兩個字串
同樣,假如沒有匹配到,會返回一個空列表物件
正則中常用的特殊序列
符號 | 描述 |
---|---|
\d | 匹配任何十進位制數字 |
\D | 匹配任何非數字字元 |
\s | 匹配任何空白字元(也就是空格) |
\S | 匹配任何非空格字元 |
\w | 匹配任何字母數字字元 |
\W | 匹配任何非字母數字字元 |
以上是6個常用的特殊序列,基本涵蓋了我們所有字串的過濾需求,序列間可以混用.
舉個簡單例子:
pattm=re.compile('\d') #找出所有的十進位制數字
pstr=pattm.findall('abcd1234')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>>> ['1', '2', '3', '4'] #返回一個數組
混用例子:
pattm=re.compile('\D\d') #找出第一位是字母,第二位是數字的組合
pstr=pattm.findall('abcd1234')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['d1'] #成功匹配到d1
正則中常用的元字元
元字元在正則表示式中是最常用也是最不容易理解的字元,下面我們會來一一介紹幾種最常用的元字元!
常用的元字元有以下幾種:
.元字元:
. ^ $ * + ? { } [ ] \ | ( )
我們來一一舉例子講解:
pattm=re.compile('.',re.S) #re.s代表匹配的模式,我們這裡選擇了所有的匹配模式,所有換行符也會被匹配
pstr=pattm.findall('abcd1234\n')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['a', 'b', 'c', 'd', '1', '2', '3', '4', '\n']
. 代表一個任意的字元,這個字元預設包含所有的不包括換行符在內的所有字元,但通過改變匹配的模式,我們也可以做到匹配換行符,所有結果中返回了所有的匹配的結果!
^ 元字元符:
pattm=re.compile('^abc',re.S) #匹配abc為開頭的字元
pstr=pattm.findall('abcd1234\n')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['abc']
^ 號表示匹配開頭,上面例子我們相當於匹配字串abc,切記這裡不是匹配到整個abc開頭的字串哦!
$ 元字元
pattm=re.compile('abc$',re.S)
pstr=pattm.findall('abcd1234abc')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['abc']
$ 表示匹配結尾,上面例子就是相當於匹配abc,注意不是得到整個以abc結尾的字串!
* 元字元
pattm=re.compile('a*',re.S) #找出所有0個a乃至n個a的匹配
pstr=pattm.findall('bcaacaaab')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['', '', 'aa', '', 'aaa', '', '']
*代表倍數,只對該符號前一個字元有效,可以是0倍也可以是任意倍數,所以上面結果中,返回了空字元,因為0倍就是空字元!!
+ 元字元
pattm=re.compile('a+',re.S)
pstr=pattm.findall('bcaacaaab')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['aa', 'aaa']
元字元+和元字元*有點類似,只對該符號前一個字元有效,也是指重複,但是+不能匹配0倍,這是根本區別!
? 元字元
pattm=re.compile('ca?t',re.S)
pstr=pattm.findall('catdddct')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['cat', 'ct']
元字元?號也是重複類字元,但他表示可選,上面例子中a字元表示可選字元,他可匹配也可以不匹配,所以返回了兩種匹配結果!
{ } 元字元
元字元{} 也是重複字元中的一員,只對該符號前一個字元有效,他比+和*更加的靈活
pattm=re.compile('a{1,2}',re.S) #最少匹配1個a,最多匹配兩個a
pstr=pattm.findall('fcabcdaaaef^')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['a', 'aa', 'a']
{}字元中可以有兩個變數{m,n}, m表示最少的匹配倍數,n表示最大的匹配倍數.也可以只寫一個變數{n},表示最大匹配n倍字元!
[] 元字元
pattm=re.compile('[abc]',re.S)
pstr=pattm.findall('abcdef')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['a', 'b', 'c']
元字元[] 表示一個範圍,相當於指定匹配一個範圍類的字元,上圖中想到與能匹配a,b,c三個字元範圍,也可以寫成[a-b]兩者的效果相同,很多手機號的正則就是利用了該元字元,比如[0-9]取0到9範圍內的一個數字!
還需要特別注意一點的是,在[]類中其他元字元將不會再有原有功能!
舉個例子:
pattm=re.compile('[abc^]',re.S) #按道理,^表示匹配開頭,應該匹配abc開頭的字元
pstr=pattm.findall('fcabcdef^')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['c', 'a', 'b', 'c', '^'] #但結果卻可以看出,因為[]類的原因,^元字元的作用消失了,被當成了普通的一個字元,返回了所有[]內字元範圍的匹配
\ 元字元
\字元是一個比較有意思的字元,他主要有兩種功能
一種是轉義:
pattm=re.compile('\{',re.S) #將{轉義成普通字元匹配
pstr=pattm.findall('fc{aa{ef[')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['{', '{']
我們可以通過\將其他的元字元當成普通字元來匹配!
第二種是組合序列,通過一些特定的組合,組合成了一些特定功能的序列,比如我們上面提到的特殊序列\s,\w等
| 元字元
pattm=re.compile('a|b',re.S)
pstr=pattm.findall('abcdbcda')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['a', 'b', 'b', 'a']
| 字元和java中的或有點類似,表示匹配前面部分或者後面部分,需要注意的是整個前面和後面部分!假如上面例子是abc|a表示式,表示匹配abc或者b,而不是先匹配ab,然後在c|a中選擇一個,這種理解是錯誤的!
( ) 元字元
()字元代表分組,代表一個整體
pattm=re.compile('(abc)',re.S) #代表匹配abc字元
pstr=pattm.findall('abcccababab')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['abc']
當然()的用法遠遠不止上面這麼簡單,我們可以在()中加入任何的一個匹配規則組成一個組,就可以實現無數種功能
比如:
pattm=re.compile('(^abc.+)',re.S)
pstr=pattm.findall('abcccababab')
if pstr!=None:
print(pstr)
else:
print('無匹配!')
>>> ['abcccababab']
上面’(^abc.+)’ 正則,如果你認真看了上面所有的元字元,應該不難理解,表示匹配abc開頭的任意長度的字串,所以上面返回了整個字串.
還有一點需要注意,記得最上面我們使用match和search函式的時候,往往列印都會使用group函式,入下:
pattm=re.compile('(^abc.+)',re.S)
pstr=pattm.search('abcccababab')
if pstr!=None:
print(pstr.group()) #使用過了group函式
else:
print('無匹配!')
其實這裡的group函式對應的就是一個正則中的()組,group(1)代表第一個出現的()組的匹配,groupe(1,3)代表出現的第1個和第三個()組的匹配!
Q&A
以上我們就介紹完了,其實正則是一個很龐大的知識,遠遠不止我們文章介紹的那幾種,但是基礎我們一定要知道,這樣在以後遇到一個複雜正則表示式的時候,至少能夠看懂一個大概的樣子.而不是一無所知!