Python常用正則表達式語法和寫法

今天因為看一個爬蟲的例子,看到數(shù)據(jù)抓取的時候別人用的正則表達式去匹配想要的數(shù)據(jù).當即對這個表達式感興趣起來,仔細閱讀了一下相關文檔,對其有了大概的認識,索性寫了一篇文章來介紹python中相關正則表達式的用法,以便自己日后參閱!

相關介紹

正則表達式是一種高度精度化的語言,我們可以用一段特定字符串生成的正則來過濾,替換,查找我們需要的數(shù)據(jù).正則表達式在運行的的時候會被編譯成一系列的碼,并由C編寫的匹配引擎執(zhí)行,一般來說效率比一般的算法效率更高,但是卻更不易于理解.大家也可以參考官方文檔.

相關的庫

Python的正則相關庫用的最多的是RE模塊了,因為是python的內(nèi)置模塊,我們只需要直接導入re模塊即可使用其功能.

re模塊常用函數(shù)用法

下面要介紹的相關函數(shù)非常重要,我們需要詳細講解一下!

1.compile 函數(shù)
    re.compile(pattern, flags=0)

compile函數(shù)類似一個正則工廠,他返回的是一個正則表達式的模式對象,我們可以用這個對象去加工任何需要加工的字符串.第一個參數(shù)傳入的是正則的表達式字符串,第二個參數(shù)傳遞的是匹配的模式.

2.match 函數(shù)
pattern=re.compile('正則字符串')
pattern.match('要匹配的字符串')

match函數(shù)是一個匹配函數(shù),我們用compile函數(shù)生成的工廠對象,對要加工的字符串進行匹配,如果有響應的字符串,就會返回,否者返回None.需要注意的是,match函數(shù)匹配字符串是從字符串開頭匹配的,假如開頭沒有找到,就不會繼續(xù)找下去!而且他只會返回最先匹配到的字符串,也就是說,假如可能一個字符串中有兩個可以匹配的地方,他只會返回最先匹配到的那部分!
舉個例子:

pattm=re.compile('a')   #a為正則字符串
pstr=pattm.match('aabcad')  #abcd是要匹配的字符串
    if pstr!=None:
        print(pstr.group())
    else:
        print('無匹配!')
>>>  a    #運行結(jié)果為a ,注意這個a是第一個a!

由于'adcd'字符串中第一位有我們需要匹配的正則字符a,所以成功匹配到了a!

pattm=re.compile('b')   #a為正則字符串
pstr=pattm.match('abcd')  #abcd是要匹配的字符串
    if pstr!=None:
        print(pstr.group())  #這里group函數(shù)下面會說
    else:
        print('無匹配!')
>>>  無匹配!    #運行沒有匹配到

上面我們改了一下正則規(guī)則為b,就是說匹配的字符串第一個字符必須為b,否者匹配不成功!

3.search 函數(shù)
pattern=re.compile('正則字符串')
pattern.search('要匹配的字符串')

search 函數(shù)和match函數(shù)有個相同點就是,他只會返回最先匹配到那部分字符串!但是他和match不用的是,他不會只局限于在字符串的開頭查找,他會查找整個字符串,直到找到匹配的部分為止!

pattm=re.compile('a')
pstr=pattm.search('baabcad')
    if pstr!=None:
        print(pstr.group())
    else:
        print('無匹配!')
>>>> a   #結(jié)果為a,這里的a是字符串出現(xiàn)的第一個a

假如字符串中沒有匹配的字符,返回None

pattm=re.compile('f')
pstr=pattm.search('baabcad')
    if pstr!=None:
        print(pstr.group())
    else:
        print('無匹配!')
>>> 無匹配!    #字符串中沒有匹配到f字符!
3.findAll 函數(shù)

findAll函數(shù)不但會查找整個字符串,并且會將匹配到的所有字符返回!而不僅限于返回第一個匹配到的!他會將返回的所有字符裝載到一個列表對象返回.

pattm=re.compile('a')
pstr=pattm.findall('baabcad')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')

 >>>>  ['a', 'a', 'a']   #返回了所有匹配到的a

同樣,假如沒有匹配到,會返回一個空列表對象

4.split函數(shù)

分割函數(shù),類似于字符串分割.會根據(jù)正則字符為基準分割我們需要的字符串.

pattm=re.compile(':')
pstr=pattm.split('baa:bcad')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
>>> ['baa', 'bcad']   #根據(jù):分割成了兩個字符串

同樣,假如沒有匹配到,會返回一個空列表對象

正則中常用的特殊序列

符號 描述
\d 匹配任何十進制數(shù)字
\D 匹配任何非數(shù)字字符
\s 匹配任何空白字符(也就是空格)
\S 匹配任何非空格字符
\w 匹配任何字母數(shù)字字符
\W 匹配任何非字母數(shù)字字符

以上是6個常用的特殊序列,基本涵蓋了我們所有字符串的過濾需求,序列間可以混用.
舉個簡單例子:

pattm=re.compile('\d')   #找出所有的十進制數(shù)字
pstr=pattm.findall('abcd1234')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
 >>>>  ['1', '2', '3', '4']   #返回一個數(shù)組

混用例子:

  pattm=re.compile('\D\d')  #找出第一位是字母,第二位是數(shù)字的組合
  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']

. 代表一個任意的字符,這個字符默認包含所有的不包括換行符在內(nèi)的所有字符,但通過改變匹配的模式,我們也可以做到匹配換行符,所有結(jié)果中返回了所有的匹配的結(jié)果!

^ 元字符符:
 pattm=re.compile('^abc',re.S)  #匹配abc為開頭的字符
 pstr=pattm.findall('abcd1234\n')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
 >>>  ['abc']   

^ 號表示匹配開頭,上面例子我們相當于匹配字符串a(chǎn)bc,切記這里不是匹配到整個abc開頭的字符串哦!

$ 元字符
  pattm=re.compile('abc$',re.S)
  pstr=pattm.findall('abcd1234abc')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
        
  >>> ['abc']

$ 表示匹配結(jié)尾,上面例子就是相當于匹配abc,注意不是得到整個以abc結(jié)尾的字符串!

* 元字符
pattm=re.compile('a*',re.S)  #找出所有0個a乃至n個a的匹配
pstr=pattm.findall('bcaacaaab')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
        
 >>> ['', '', 'aa', '', 'aaa', '', '']

*代表倍數(shù),只對該符號前一個字符有效,可以是0倍也可以是任意倍數(shù),所以上面結(jié)果中,返回了空字符,因為0倍就是空字符!!

+ 元字符
pattm=re.compile('a+',re.S)
pstr=pattm.findall('bcaacaaab')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
>>>  ['aa', 'aaa']

元字符+和元字符*有點類似,只對該符號前一個字符有效,也是指重復,但是+不能匹配0倍,這是根本區(qū)別!

? 元字符
 pattm=re.compile('ca?t',re.S)  
 pstr=pattm.findall('catdddct')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
        
   >>> ['cat', 'ct']   

元字符?號也是重復類字符,但他表示可選,上面例子中a字符表示可選字符,他可匹配也可以不匹配,所以返回了兩種匹配結(jié)果!

{ } 元字符

元字符{} 也是重復字符中的一員,只對該符號前一個字符有效,他比+和*更加的靈活

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表示最少的匹配倍數(shù),n表示最大的匹配倍數(shù).也可以只寫一個變量{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范圍內(nèi)的一個數(shù)字!

還需要特別注意一點的是,在[]類中其他元字符將不會再有原有功能!

舉個例子:

pattm=re.compile('[abc^]',re.S)  #按道理,^表示匹配開頭,應該匹配abc開頭的字符
pstr=pattm.findall('fcabcdef^')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
        
  >>> ['c', 'a', 'b', 'c', '^']  #但結(jié)果卻可以看出,因為[]類的原因,^元字符的作用消失了,被當成了普通的一個字符,返回了所有[]內(nèi)字符范圍的匹配
\ 元字符

\字符是一個比較有意思的字符,他主要有兩種功能

一種是轉(zhuǎn)義:

pattm=re.compile('\{',re.S)   #將{轉(zhuǎn)義成普通字符匹配
pstr=pattm.findall('fc{aa{ef[')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
  >>> ['{', '{']

我們可以通過\將其他的元字符當成普通字符來匹配!

第二種是組合序列,通過一些特定的組合,組合成了一些特定功能的序列,比如我們上面提到的特殊序列\(zhòng)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']

當然()的用法遠遠不止上面這么簡單,我們可以在()中加入任何的一個匹配規(guī)則組成一個組,就可以實現(xiàn)無數(shù)種功能

比如:

pattm=re.compile('(^abc.+)',re.S)
pstr=pattm.findall('abcccababab')
    if pstr!=None:
        print(pstr)
    else:
        print('無匹配!')
 >>> ['abcccababab']

上面'(^abc.+)' 正則,如果你認真看了上面所有的元字符,應該不難理解,表示匹配abc開頭的任意長度的字符串,所以上面返回了整個字符串.

還有一點需要注意,記得最上面我們使用match和search函數(shù)的時候,往往打印都會使用group函數(shù),入下:

pattm=re.compile('(^abc.+)',re.S)
pstr=pattm.search('abcccababab')
    if pstr!=None:
        print(pstr.group())  #使用過了group函數(shù)
    else:
        print('無匹配!')

其實這里的group函數(shù)對應的就是一個正則中的()組,group(1)代表第一個出現(xiàn)的()組的匹配,groupe(1,3)代表出現(xiàn)的第1個和第三個()組的匹配!

Q&A

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缺亮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子羔巢,更是在濱河造成了極大的恐慌民宿,老刑警劉巖景馁,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饥悴,死亡現(xiàn)場離奇詭異故慈,居然都是意外死亡,警方通過查閱死者的電腦和手機阅酪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門旨袒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人术辐,你說我怎么就攤上這事砚尽。” “怎么了辉词?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵必孤,是天一觀的道長。 經(jīng)常有香客問我瑞躺,道長敷搪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任幢哨,我火速辦了婚禮赡勘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘱么。我一直安慰自己狮含,他們只是感情好顽悼,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布曼振。 她就那樣靜靜地躺著,像睡著了一般蔚龙。 火紅的嫁衣襯著肌膚如雪冰评。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天木羹,我揣著相機與錄音甲雅,去河邊找鬼解孙。 笑死,一個胖子當著我的面吹牛抛人,可吹牛的內(nèi)容都是我干的弛姜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼妖枚,長吁一口氣:“原來是場噩夢啊……” “哼廷臼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起绝页,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤荠商,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后续誉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體莱没,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年酷鸦,在試婚紗的時候發(fā)現(xiàn)自己被綠了饰躲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡臼隔,死狀恐怖属铁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情躬翁,我是刑警寧澤焦蘑,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站盒发,受9級特大地震影響例嘱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宁舰,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一拼卵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛮艰,春花似錦腋腮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至袜刷,卻和暖如春聪富,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背著蟹。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工墩蔓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留梢莽,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓奸披,卻偏偏與公主長得像昏名,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子阵面,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容