1. 程式人生 > >Python正則之再學習與實踐

Python正則之再學習與實踐

昨天做網頁爬取的時候,感覺自己對正則不熟悉的很,故今天再花上午時間認真整理下,不可懈怠。

1.常見正則表示式符號
[1].literal    匹配文字字串的字面值literal    
[2].re1|re2    匹配正則表示式re1或者re2        foo | bar
[3]..        匹配任何字元(除\n)        b.b
[4].^        匹配字串的起始部分        ^Dear
[5].$        匹配字串的終止部分        /bin/*sh$
[6].*        匹配0次或多次前面出現的正則表示式    [A-Za-z0-9]*    
[7].+        匹配1次或者多次前面出現的正則表示式    [a-z]+\.com
[8].?        匹配0次或1次前面出現的正則表示式        goo?
[9].{N}        匹配N次前面出現的正則表示式        [0-9]{3}
[10].{M,N}    匹配M~N次前面出現的正則表示式        [0-9]{5,9}
[11].[...]    匹配來自字符集的多個字元            [aeiou]
[12].[..x-y..]    匹配x-y範圍內的任意單一字元        [0-9a-zA-Z]
[13].[^...]    不匹配此字符集中出現的任何一個字元,包括某一範圍內的字元    [^fsdlkj] [^a-z]
[14].(*|+|?|{})? 用於匹配上面頻繁出現的符號的非貪婪版本    .*?[a-z]
[15].(...)    匹配封閉的正則表示式,然後另存為子組    ([0-9]{3})?, f(oo|u)bar

2.特殊字元
[1].\d        匹配任何十進位制數字,與[0-9]一致(\D表示不匹配任何非數值型的數字)    data\d+.txt
[2].\w        匹配任何字母數字字元,與[0-9a-zA-Z]相同(\W與之相反)    [A-Za-z]\w+
[3].\s        匹配任何空格字元(\S與之相反)    of\sthe
[4].\b        匹配任何單詞邊界(\B與之相反)    \bThe\b
[5].\Number    匹配已儲存的子組Number        price:\16
[6].\c        僅按字面意思匹配,不匹配特殊含義    \., \\, \*
[7].\A(\Z)    匹配字串的開始(結束)    \ADear

3.使用圓括號指定分組
有些時候,我們不僅對之前匹配成功的資料更感興趣,而且想要知道能否提取任何已經匹配成功的特定字串或者子字串。為了解決這個問題,只要用一對圓括號包裹任何正則表示式。
當使用圓括號時,一對圓括號可以實現以下任意一個功能:1)對正則表示式進行分組;2)匹配分組。
\d+(\.\d*)?    表示簡單浮點數的字串,也就是說,任何十進位制數字,後面可以接一個小數點和零個或者多個十進位制數字,例如"0.004","2","75."
(Mr?s?)?[A-Z][a-z]*[A-Za-z-]+    名字和姓氏,以及對名字的限制(如果有,首字母必須大寫,後續字母小寫),全名前可以有可選的"Mr.","Mrs.","Ms."或者"M."作為稱謂,以及可選的姓氏,可以有多個單詞、橫線以及大寫字母。

4.re模組核心函式和方法
[1].僅僅是re模組函式
compile(pattern, flags=0)    使用任何可選的標記來編譯正則表示式的模式,然後返回一個正則表示式物件

[2].re模組和正則表示式物件的方法
match(pattern, string, flags=0)        嘗試使用帶有可選的標記的正則表示式的模式來匹配字串。如果匹配成功,就返回匹配物件,如果失敗,就返回None。

search(pattern, string, flags=0)    使用可選標記搜尋字串中第一次出現的正則表示式的模式來搜尋字串,如果搜尋成功,則返回匹配的字串;否則返回None

findall(pattern, string[,flags])    查詢字串中所有(非重複)出現的正則表示式模式,findall方法總是返回一個列表,如果匹配成功,列表將包含所有成功匹配的部分(從左向右順序排列),如果失敗則返回一個空列表。
子組在一個更復雜的返回列表中搜索結果,而且這樣做是有意義的,因為子組是允許從單個正則表示式中抽取特定模式的一種機制。
Example:
# 使用findall和finditer查詢每一次出現的位置
s = 'This and that and This and that'
lists = re.findall(r'(th\w+) and (th\w+)', s, re.I)
print(lists)

Result:
[('This', 'that'), ('This', 'that')]

finditer(pattern, string[, flags])    與findall函式相同,但返回的不是一個列表,而是一個迭代器。它的優點在於更節省記憶體資源。
iters = pattern.finditer('dottt0999-ewar3223--AAnot333423-fsd-0')
for iter in iters:
    print(iter.group())

split(pattern, string, max=0)    

sub(pattern, repl, string, count=0)    使用repl替換所有正則表示式的模式在字串中出現的位置,除非定義count,否則將替換所有出現的位置

[3].常見的匹配物件方法
group(num=0)    返回整個匹配物件,或者編號為num的子組
groups(default=None)    返回一個包含所有匹配子組的元組(如果沒有成功匹配,則返回一個空元祖)
groupdict(default=None)        返回一個包含所有匹配的命名子組的字典,所有的子組名稱作為字典的鍵(如果沒有成功匹配,就返回一個空字典)
groupdict看似很難,但通過例子可以相當便利的理解:
Example:
match = re.search(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?:\d{4})',
                   '(800) 555-1212')
print( match.groupdict() )
Result:
{'prefix': '555', 'areacode': '800'}
意思是,如果給分組起了別名,那麼在groupdict中就會顯示以別名為鍵,正則模式匹配字元為值的字典。

[4].常用的屬性模組
re.I    不區分大小寫的匹配
re.L    根據所使用的本地語言環境通過\w,\W,\b,\B,\s,\S實現匹配
re.M    ^和$分別匹配目標字串中的行的起始和結尾,而不是嚴格匹配整個字串本身的起始和結尾。
re.S    '.'號通常匹配除了\n之外的所有單個字元;該標記表示'.'號能夠匹配全部字元

5.常見用法:
[1].匹配多個字串
bt = 'bat|bet|bit'
m = re.match(bt, 'bat')
if m is not None:
    print(m.group())

[2].特殊含義的字元匹配
., *, ?, (, ), +, ... 這些字元都需要轉義後才能匹配字串中原有字元。
比如字串為[email protected],那麼需要使用(\w+)@(\w+)\.com才能匹配,注意其中的.的轉義。

[3].從單個正則表示式中抽取特定模式(使用分組)
例如我們想要匹配一個完整電話號碼中的一部分,例如區號; 或者完整電子郵件地址的一部分,例如登入名稱。
Example:
s = 'This and that'
print( re.findall(r'(th\w+) and (th\w+)', s, re.I) )

Result:
[('This', 'that')]

[4].將美式的日期表示法MM/DD/YY{,YY}格式轉換為其他國家常用的格式DD/MM/YY{,YY}
可以使用\N取出匹配分組,其中N是在替換字串中使用的分組編號。

很奇怪:
s = "i love you so dont let me upset"
lists = re.findall(r'(?#This is wonderful)(?P<tag>\b.*?o.*?\b)', s, re.S)
的結果為什麼是:['i love', ' you', ' so', ' dont']呢?為什麼是'i love'?