(常用)re模塊


re模塊(正則)
#re:一些帶有特殊含義的符號或者符號的組合
#為什么要用re:一堆字符串中找到你所需要的內容,過濾規則是什么樣,通過re模塊功能來告訴計算機你的過濾規則
#應用:在爬蟲中最為常用;使用爬蟲時有其他模塊可以導入幫助clear數據,正則也可用於其他方面
#原理:re模塊的內部實現 不是python 而是 調用了c庫
import re
print(re.findall(' \w','ab 12\+- *&_'))
print(re.findall('\W','ab 12\+- *&_'))
print(re.findall(' \s','ab \r1\n2\t\+- *&_'))
print(re.findall('\S','ab \r1\n2\t\+- *&_'))
print(re.findall(' \d','ab \r1\n2\t\+- *&_'))
print(re.findall('\D','ab \r1\n2\t\+- *&_'))
print(re.findall('\w_sb','egon alex_sb123123wxx_sb,lxx_sb'))
print(re.findall(' \Aalex','abcalex is salexb'))
print(re.findall('\Aalex','alex is salexb'))
print(re.findall(' ^alex','alex is salexb'))
print(re.findall('sb \Z','alexsb is sbalexbsb'))
print(re.findall('sb $','alexsb is sbalexbsb'))
print(re.findall('^ebn$','ebn1')) #^ebn$ 篩出的就是ebn(以ebn開頭,以ebn結尾)
print(re.findall('a \nc','a\nc a\tc a1c'))
\t為制表符,在不同平台表示不同的空個數
\A  ^     #使用^
\Z  $     #使用$
# 重復匹配:
#.   ?   *   +  {m,n}  .*  .*?  {m}
1、 .:代表 除了換行符外任意一個字符 
. 除了換行符之外的任意一個字符, 如果想不除換行符,后加re.DOTALL
print(re.findall('a.c','abc a1c aAc aaaaaca\nc'))
print(re.findall('a.c','abc a1c aAc aaaaaca\nc' ,re.DOTALL))
2、 :代表 左邊那一個字符重復 0次或1次 默認貪婪(能匹配1次絕不匹配0次)
?不能單獨使用
print(re.findall('ab?','a ab abb abbb abbbb abbbb'))
3、 *:代表 左邊那一個字符出現 0次或無窮次 默認貪婪(能匹配無窮次絕不匹0次)
print(re.findall('ab*','a ab abb abbb abbbb abbbb a1bbbbbbb'))
4、 + :代表 左邊那一個字符出現 1次或無窮次 默認貪婪(能匹配無窮次絕不匹配1次)
print(re.findall('ab+','a ab abb abbb abbbb abbbb a1bbbbbbb'))
5、{m,n}:代表 左邊那一個字符出現 m次到n次  默認貪婪(能匹配n次絕不匹配m次)
print(re.findall('ab?','a ab abb abbb abbbb abbbb'))
print(re.findall('ab{0,1}','a ab abb abbb abbbb abbbb'))
print(re.findall('ab*','a ab abb abbb abbbb abbbb a1bbbbbbb'))
print(re.findall('ab{0,}','a ab abb abbb abbbb abbbb a1bbbbbbb'))
print(re.findall('ab+','a ab abb abbb abbbb abbbb a1bbbbbbb'))
print(re.findall('ab{1,}','a ab abb abbb abbbb abbbb a1bbbbbbb'))
print(re.findall('ab{1,3}','a ab abb abbb abbbb abbbb a1bbbbbbb'))
6、 .*:匹配 任意長度,任意的字符=====》 貪婪
print(re.findall('a.*c','ac a123c aaaac a *123)()c asdfasfdsadf'))
7、 .*?多少次到多少次(貪婪)+ ?=非貪婪
print(re.findall('a.*?c','a123c456c'))
():分組
print(re.findall('(alex)_sb','alex_sb asdfsafdafdaalex_sb'))
print(re.findall(
    ' href="(.*?)"',
    '<li><a id="blog_nav_sitehome" class="menu" href="http://www.cnblogs.com/">博客園</a></li>')
)
[]:匹配一個指定 范圍內的字符(這一個字符來自於括號內定義的)
[] 內寫什么就是其單獨的意義, 可寫0-9 a-zA-Z
print(re.findall('a[0-9][0-9]c','a1c a+c a2c a9c a11c a-c acc aAc'))
當-需要被當中普通符號匹配時,只能放到[]的最左邊或最 右邊
a-b有特別的意思,所以如果想讓-表示它本身,要將其放在最左或最右
print(re.findall('a[-+*]c','a1c a+c a2c a9c a*c a11c a-c acc aAc'))
print(re.findall('a[a-zA-Z]c','a1c a+c a2c a9c a*c a11c a-c acc aAc'))
[]內的^代表取反的意思 (^在[]中表示取反)
print(re.findall('a[^a-zA-Z]c','a c a1c a+c a2c a9c a*c a11c a-c acc aAc'))
print(re.findall('a[^0-9]c','a c a1c a+c a2c a9c a*c a11c a-c acc aAc'))
print(re.findall('([a-z]+)_sb','egon alex_sb123123wxxxxxxxxxxxxx_sb,lxx_sb'))
| :或者
print(re.findall('compan(ies|y)','Too many companies have gone bankrupt, and the next one is my company'))
(?:   ):代表取匹配成功的所有內容,而不僅僅只是括號內的內容 ((?:   )表示匹配的結果都要,不單單要()內的
print(re.findall('compan(?:ies|y)','Too many companies have gone bankrupt, and the next one is my company'))
print(re.findall('alex|sb','alex sb sadfsadfasdfegon alex sb egon'))
re模塊的其他方法:
print( re.findall('alex|sb','123123 alex sb sadfsadfasdfegon alex sb egon'))
print (re.search('alex|sb','123213 alex sb sadfsadfasdfegon alex sb egon').group())
print(re.search('^alex','123213 alex sb sadfsadfasdfegon alex sb egon'))
print(re.search('^alex','alex sb sadfsadfasdfegon alex sb egon').group())
re.search, 取第一個結果,若沒有返回None;若想讓結果直接顯示后加group();返回None時用group()會報錯
re.match 相當於^版本的search
print(re.match('alex','alex sb sadfsadfasdfegon alex sb egon').group())
print(re.match('alex','123213 alex sb sadfsadfasdfegon alex sb egon'))
re.match 相當於^版本的search
re.split與split相比,內部可以使用正則表達式
info='a:b:c:d'
print(info.split(':'))
print(re.split(':',info))
info=r'get :a.txt\3333/rwx'
print(re.split('[ :\\\/]',info))
re.sub 與replace相比,內部可以使用正則表達式
print('egon is beutifull egon'.replace('egon','EGON',1))
print(re.sub('(.*?)(egon)(.*?)(egon)(.*?)',r'\1\2\3EGON\5','123 egon is beutifull egon 123'))
print(re.sub('(lqz)(.*?)(SB)',r'\3\2\1',r'lqz is SB'))
print(re.sub('([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)',r'\5\2\3\4\1',r'lqzzzz123+ is SB'))
太常用的表達式可以做成
pattern= re.compile('alex')
print (pattern.findall('alex is alex alex'))
print(pattern.findall('alexasdfsadfsadfasdfasdfasfd is alex alex'))
 
斷言
 正則表達式中的斷言,作為 高級應用出現,倒不是因為它有多難,而是概念比較抽象,不容易理解而已。
  如果不用斷言,以往用過的那些表達式,僅僅能獲取到有規律的字符串,而不能獲取無規律的字符串。
舉個例子,比如html源碼中有<title>xxx</title>標簽,用以前的知識,我們只能確定源碼中的<title>和</title>是固定不變的。因此,如果想獲取頁面標題(xxx),充其量只能寫一個類似於這樣的表達式:<title>.*</title>,而這樣寫匹配出來的是完整的<title>xxx</title>標簽,並不是單純的頁面標題xxx。
       想解決以上問題,就要用到斷言知識。
       在講斷言之前,讀者應該 先了解分組,這有助於理解斷言。
       分組在正則中用()表示,根據小菜理解,分組的作用有兩個:
       n  將某些規律看成是一組,然后進行組級別的重復,可以得到意想不到的效果。
       n  分組之后,可以通過后向引用簡化表達式。
       先來看第一個作用,對於IP地址的匹配,簡單的可以寫為如下形式:
       \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}
       但仔細觀察,我們可以發現一定的規律,可以把.\d{1,3}看成一個整體,也就是把他們看成一組,再把這個組重復3次即可。表達式如下:
       \d{1,3}(.\d{1,3}){3}
這樣一看,就比較簡潔了。
再來看第二個作用,就拿匹配<title>xxx</title>標簽來說,簡單的正則可以這樣寫:
       <title>.*</title>
       可以看出,上邊表達式中有兩個title,完全一樣,其實可以通過分組簡寫。表達式如下:
       <(title)>.*</\1>
       這個例子實際上就是 反向引用的實際應用對於分組而言,整個表達式永遠算作第0組,在本例中,第0組是<(title)>.*</\1>,然后從左到右,依次為分組編號,因此,(title)是第1組
       用\1這種語法,可以引用某組的文本內容,\1當然就是引用第1組的文本內容了,這樣一來,就可以簡化正則表達式,只寫一次title,把它放在組里,然后在后邊引用即可。
       以此為啟發,我們可不可以簡化剛剛的IP地址正則表達式呢?原來的表達式為\d{1,3}(.\d{1,3}){3},里邊的\d{1,3}重復了兩次,如果利用后向引用簡化,表達式如下:
       (\d{1,3})(.\1){3}
       簡單的解釋下,把\d{1,3}放在一組里,表示為(\d{1,3}),它是第1組,(.\1)是第2組,在第2組里通過\1語法,后向引用了第1組的文本內容。
       經過實際測試,會發現這樣寫是錯誤的,為什么呢?
       小菜一直在強調,后向引用,引用的僅僅是文本內容,而不是正則表達式!
       也就是說,組中的內容一旦匹配成功,后向引用,引用的就是匹配成功后的內容,引用的是結果,而不是表達式。
       因此,(\d{1,3})(.\1){3}這個表達式實際上匹配的是四個數都相同的IP地址,比如:123.123.123.123。
       至此,讀者已經掌握了傳說中的后向引用,就這么簡單。
       接下來說說什么是斷言。
       所謂斷言,就是指明某個字符串前邊或者后邊,將會出現滿足某種規律的字符串。
       就拿文章開篇的例子來說, 我們想要的是xxx,它沒有規律,但是它前邊肯定會有<title>,后邊肯定會有</title>,這就足夠了。
       想指定xxx前肯定會出現<title>,就用正后發斷言,表達式:(?<=<title>).*
       向指定xxx后邊肯定會出現</title>,就用正先行斷言,表達式:.*(?=</title>)
       兩個加在一起,就是(?<=<title>).*(?=</title>)
       這樣就能匹配到xxx。
     
       其實掌握了規律,就很簡單了,無論是先行還是后發,都是相對於xxx而言的,也就是相對於目標字符串而言。
       假如目標字符串后邊有條件,可以理解為目標字符串在前,就用先行斷言,放在目標字符串之后。
       假如目標字符串前邊有條件,可以理解為目標字符串在后,就用后發斷言,放在目標字符串之前。
       假如指定滿足某個條件,就是正。
       假如指定不滿足某個條件,就是負。
       斷言只是條件,幫你找到真正需要的字符串,本身並不會匹配!
 
    

(?=X )
零寬度正先行斷言。僅當子表達式 X 在 此位置的右側匹配時才繼續匹配。例如,/w+(?=/d) 與后跟數字的單詞匹配,而不與該數字匹配。 此構造不會回溯。
(?!X)
零寬度負先行斷言。僅當子表達式 X 不在 此位置的右側匹配時才繼續匹配。例如,例如,/w+(?!/d) 與后不跟數字的單詞匹配,而不與該數字匹配 。
(?<=X)
零寬度正后發斷言。僅當子表達式 X 在 此位置的左側匹配時才繼續匹配。例如,(?<=19)99 與跟在 19 后面的 99 的實例匹配。 此構造不會回溯。
(?<!X)
零寬度負后發斷言。僅當子表達式 X 不在此位置的左側匹配時才繼續匹配。例如,(?<!19)99 與不跟在 19 后面的 99 的實例匹配


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM