1. 程式人生 > >Python常用正則表示式語法和寫法

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

以上我們就介紹完了,其實正則是一個很龐大的知識,遠遠不止我們文章介紹的那幾種,但是基礎我們一定要知道,這樣在以後遇到一個複雜正則表示式的時候,至少能夠看懂一個大概的樣子.而不是一無所知!