Python學習:13.Python正則表達式
一、正則表達式簡介
正則表達式是一個特殊的字符序列,它能幫助你方便的檢查一個字符串是否與某種模式匹配。 Python 自1.5版本起增加了re 模塊,它提供 Perl 風格的正則表達式模式。
就其本質而言,正則表達式(或 RE)是一種小型的、高度專業化的編程語言, (在Python中)它內嵌在Python中,並通過 re 模塊實現。正則表達式模式被 編譯成一系列的字節碼,然後由用 C 編寫的匹配引擎執行。
re 模塊使 Python 語言擁有全部的正則表達式功能。 compile 函數根據一個模式字符串和可選的標誌參數生成一個正則表達式對象。該對象擁有一系列方法用於正則表達式匹配和替換。 re 模塊也提供了與這些方法功能完全一致的函數,這些函數使用一個模式字符串做為它們的第一個參數。
二、字符匹配
1.普通字符:大多數字符和字母都會和自身匹配
>>> re.findall("alexsel","gtuanalesxalexselericapp") [‘alexsel‘] >>> re.findall("alexsel","gtuanalesxalexswxericapp") [] >>> re.findall("alexsel","gtuanalesxalexselwupeiqialexsel") [‘alexsel‘, ‘alexsel‘]
2.元字符: . ^ $ * + ? { } [ ] | ( ) \
- . :匹配一個除了換行符任意一個字符
>>> re.findall("alexsel.w","aaaalexselaw") [‘alexselaw‘] #一個點只能匹配一個字符
- ^ :只有後面跟的字符串在開頭,才能匹配上
>>> re.findall("^alexsel","gtuanalesxalexselgeappalexsel") [] >>> re.findall("^alexsel","alexselgtuanalesxalexselwgtappqialexsel") [‘alexsel‘] #"^"這個符號控制開頭,所以寫在開頭
- $ :只有它前面的字符串在檢測的字符串的最後,才能匹配上
>>> re.findall("alexsel$","alexselseguanalesxalexselganapp") [] >>> re.findall("alexsel$","alexselgtaanalesxalexsssiqialexsel") [‘alexsel‘]
- * :它控制它前面那個字符,他前面那個字符出現0到多個都可以匹配上
>>> re.findall("alexsel*","aaaalexse") [‘alexse‘] >>> re.findall("alexsel*","aaaalexsel") [‘alexsel‘] >>> re.findall("alex*","aaaalexsellllll") [‘alexsellllll‘]
- + :匹配前面那個字符1到多次
>>> re.findall("alexsel+","aaaalexselll") [‘aleselll‘] >>> re.findall("alexsel+","aaaalexsel") [‘alexsel‘] >>> re.findall("alexsel+","aaaalexse") []
- ? :匹配前面那個字符0到1個,多余的只匹配一個
>>> re.findall("alexsel?","aaaalexse") [‘ale‘] >>> re.findall("alexsel?","aaaalexsel") [‘alexsel‘] >>> re.findall("alexsel?","aaaalexsellll") [‘alexsel‘]
- {} :控制它前面一個字符的匹配個數,可以有區間(閉區間),有區間的情況下按照多的匹配
>>> re.findall("alexsel{3}","aaaalexselllll") [‘alexselll‘] >>> re.findall("alexsel{3}","aaaalexsell") [] >>> re.findall("alexsel{3}","aaaalexse") [] >>> re.findall("alexsel{3}","aaaalexselll") [‘alexselll‘] >>> re.findall("alexsel{3,5}","aaaalexsellllllll") [‘alexselllll‘] >>> re.findall("alexsel{3,5}","aaaalexselll") [‘alexselll‘] >>> re.findall("alexsel{3,5}","aaaalexsell") []
- \ :
後面跟元字符去除特殊功能,
後面跟普通字符實現特殊功能。
引用序號對應的字組所匹配的字符串 (一個括號為一個組)。
在開頭加上 r 表示不轉義。
#\2 就相當於第二個組(eric) >>> re.search(r"(alexsel)(eric)com\2","alexselericcomeric").group() ‘alexselericcomeric‘ >>> re.search(r"(alexsel)(eric)com\1","alexselericcomalex").group() ‘alexselericcomalex‘ >>> re.search(r"(alexsel)(eric)com\1\2","alexselericcomalexseleric").group() ‘alexselericcomalexeric‘
\d :匹配任何十進制數;它相當於類[0-9]
>>> re.findall("\d","aaazz1111344444c") [‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘3‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘] >>> re.findall("\d\d","aaazz1111344444c") [‘11‘, ‘11‘, ‘34‘, ‘44‘, ‘44‘] >>> re.findall("\d0","aaazz1111344444c") [] >>> re.findall("\d3","aaazz1111344444c") [‘13‘] >>> re.findall("\d4","aaazz1111344444c") [‘34‘, ‘44‘, ‘44‘]
\D :匹配任何非數字字符;它相當於類[^0-9]
>>> re.findall("\D","aaazz1111344444c") [‘a‘, ‘a‘, ‘a‘, ‘z‘, ‘z‘, ‘c‘] >>> re.findall("\D\D","aaazz1111344444c") [‘aa‘, ‘az‘] >>> re.findall("\D\d\D","aaazz1111344444c") [] >>> re.findall("\D\d\D","aaazz1z111344444c") [‘z1z‘]
\s :匹配任何空白字符;它相當於類[ \t\n\r\f\v]
>>> re.findall("\s","aazz1 z11..34c") [‘ ‘]
\S :匹配任何非空白字符;它相當於類[^ \t\n\r\f\v]
\w :匹配任何字母數字字符;他相當於類[a-zA-Z0-9_]
>>> re.findall("\w","aazz1z11..34c") [‘a‘, ‘a‘, ‘z‘, ‘z‘, ‘1‘, ‘z‘, ‘1‘, ‘1‘, ‘3‘, ‘4‘, ‘c‘]
\W :匹配任何非字母數字字符;它相當於類[^a-zA-Z0-9_]
\b :匹配一個單詞邊界,也就是指單詞和空格間的位置
>>> re.findall(r"\babc\b","abc sdsadasabcasdsadasdabcasdsa") [‘abc‘] >>> re.findall(r"\balexsel\b","abc alexsel abcasdsadasdabcasdsa") [‘alexsel‘] >>> re.findall("\\balexsel\\b","abc alexsel abcasdsadasdabcasdsa") [‘alexsel‘] >>> re.findall("\balexsel\b","abc alexsel abcasdsadasdabcasdsa") []
() :把括號內字符作為一個整體去處理
>>> re.search(r"a(\d+)","a222bz1144c").group() ‘a222‘ >>> re.findall("(ab)*","aabz1144c") [‘‘, ‘ab‘, ‘‘, ‘‘, ‘‘, ‘‘, ‘‘, ‘‘, ‘‘] #將括號裏的字符串作為整和後面字符逐個進行匹配,在這裏就首先將後面字符串裏的a和ab進 #行匹配,開頭匹配成功,在看看後面是a,和ab中的第二個不匹配,然後就看後面字符串中的第二個a,和ab匹配,首先a匹配成功,b也匹配成功,拿到匹配 #然後在看後面字符串中的第三個是b,開頭匹配失敗,到第四個,後面依次 >>> re.search(r"a(\d+)","a222bz1144c").group() ‘a222‘ >>> re.search(r"a(\d+?)","a222bz1144c").group() +的最小次數為1 ‘a2‘ >>> re.search(r"a(\d*?)","a222bz1144c").group() *的最小次數為0 ‘a‘
#非貪婪匹配模式 加? ,但是如果後面還有匹配字符,就無法實現非貪婪匹配 #(如果前後均有匹配條件,則無法實現非貪婪模式) >>> re.findall(r"a(\d+?)b","aa2017666bz1144c") [‘2017666‘] >>> re.search(r"a(\d*?)b","a222bz1144c").group() ‘a222b‘ >>> re.search(r"a(\d+?)b","a277722bz1144c").group() ‘a277722b‘
元字符在字符集裏就代表字符,沒有特殊意義(有幾個例外)
>>> re.findall("a[.]d","aaaacd") [] >>> re.findall("a[.]d","aaaa.d") [‘a.d‘]
例外
[-] [^] [\]
[-]
#匹配單個字符,a到z所有的字符 >>> re.findall("[a-z]","aaaa.d") [‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘d‘] >>> re.findall("[a-z]","aaazzzzzaaccc") [‘a‘, ‘a‘, ‘a‘, ‘z‘, ‘z‘, ‘z‘, ‘z‘, ‘z‘, ‘a‘, ‘a‘, ‘c‘, ‘c‘, ‘c‘] >>> >>> re.findall("[1-3]","aaazz1111344444c") [‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘3‘]
[^]
#匹配除了這個範圍裏的字符,(^在這裏有 非 的意思) >>> re.findall("[^1-3]","aaazz1111344444c") [‘a‘, ‘a‘, ‘a‘, ‘z‘, ‘z‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘c‘] >>> re.findall("[^1-4]","aaazz1111344444c") [‘a‘, ‘a‘, ‘a‘, ‘z‘, ‘z‘, ‘c‘]
[\]
>>> re.findall("[\d]","aazz1144c") [‘1‘, ‘1‘, ‘4‘, ‘4‘]
我們首先考察的元字符是"[" 和 "]"。它們常用來指定一個字符類別,所謂字符類 別就是你想匹配的一個字符集。字符可以單個列出,也可以用“-”號分隔的兩個給定 字符來表示一個字符區間。例如,[abc] 將匹配"a", "b", 或 "c"中的任意一個字 符;也可以用區間[a-c]來表示同一字符集,和前者效果一致。如果你只想匹配小寫 字母,那麽 RE 應寫成 [a-z],元字符在類別裏並不起作用。例如,[akm$]將匹配字符"a", "k", "m", 或 "$" 中 的任意一個;"$"通常用作元字符,但在字符類別裏,其特性被除去,恢復成普通字符。
三、Python正則表達式各種函數以及參數解析
match: re.match(pattern,string,flags=0)
flags 編譯標誌位,用於修改正則表達式的匹配方式,如:是否區別大小寫
re.match("com","comwww.runcomoob").group()
‘com‘ re.match("com","Comwww.runComoob",re.I).group()
‘Com‘
flags 編譯標誌位
re.I 使匹配對大小寫不敏感
>>> re.search("com","COM",re.I).group() ‘COM‘
re.L 做本地化識別(locale-aware)匹配
re.M 多行匹配,影響^和$
re.S 使.匹配包括換行在內的所有字符
>>> re.findall(".","abc\nde") [‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘] >>> re.findall(".","abc\nde",re.S) [‘a‘, ‘b‘, ‘c‘, ‘\n‘, ‘d‘, ‘e‘]
re.U 根據Unicode字符集解析字符。這個標誌影響 \w, \W, \b, \B
re.X 該標誌通過給予你更靈活的格式以便你將正則表達式寫得更易於理解。
search:re.search(pattern,string,flags=0)
re.search("\dcom","www.4comrunoob.5com").group() ‘4com‘
re.match與re.search的區別
re.match只匹配字符串的開始,如果字符串開始不符合正則表達式,則匹配失敗,函數返回None;而re.search匹配整個字符串,直到找到一個匹配。
match和search一旦匹配成功,就是一個match object對象,而match object對象有以下方法:
- group() 返回被RE匹配的字符串
- start() 返回匹配開始的位置
- end() 返回匹配結束的位置
- span() 返回一個元組包含匹配(開始,結束)的位置
- group() 返回re整體匹配的字符串,可以一次輸入多個組號,對應組號匹配的字符串,獲取匹配到的所有結果(無論是否有組)
- a. group () 返回re整體匹配的字符串,
- b. group (n,m) 返回組號為n,m所匹配的字符串,如果組號不存在,則返回indexError異常
- c. groups() groups() 方法返回一個包含正則表達式中所有小組字符串的元組,從 1 到所含的小組號,通常groups()不需要參數,返回一個元組,元組中的元就是正則表達式中定義的組。
a = "123abc456" re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整體 re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123 re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456
在上面的代碼練習中,我們看到很多代碼後面加有group,在這我們就針對這個group進行解析。
m = re.match("([abc])+", "abc")
一般,m.group(N) 返回第N組括號匹配的字符。 而m.group() == m.group(0) == 所有匹配的字符,與括號無關,這個是API規定的。 m.groups() 返回所有括號匹配的字符,以tuple格式。m.groups() == (m.group(0), m.group(1), ...)
sub subn:
re.sub(pattern, repl, string, max=0)
>>> re.sub("g.t","have","I get A, I got B, I gut C")#匹配g.t字符,用have替換(.匹配一個除了換行符任意一個字符) ‘I have A, I have B, I have C‘ >>> re.sub("got","have","I get A, I got B, I gut C") ‘I get A, I have B, I gut C‘ >>> re.sub("g.t","have","I get A, I got B, I gut C",2)#替換兩個 ‘I have A, I have B, I gut C‘ >>> re.sub("g.t","have","I get A, I got B, I gut C",1) ‘I have A, I got B, I gut C‘ >>> re.subn("g.t","have","I get A, I got B, I gut C")#使用re.subn顯示替換裏多少個 (‘I have A, I have B, I have C‘, 3)
re.compile(strPattern[, flag]):
這個方法是Pattern類的工廠方法,用於將字符串形式的正則表達式編譯為Pattern對象。
第二個參數flag是 匹配模式,取值可以使用按位或運算符‘|‘表示同時生效,比如re.I | re.M可以把正則表達式編譯成一個正則表達式對象。可以把那些經常使用的正則表達式編譯成正則表達式對象,這樣可以提高一定的效率。
一個正則表達式對象的一個例子:
>>> text = "JGood is a handsome boy, he is cool, clever, and so on..." >>> regex = re.compile(r"\w*oo\w*") >>> print regex.findall(text) [‘JGood‘, ‘cool‘]
split:
p = re.compile(r"\d+") #+:匹配前面那個字符1到多次 p.split("one1two2three3four4") #spilt分割 >>> p = re.compile(r"\d+") >>> p.split("one1two2three3four4") [‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘‘] re.split("\d+","one1two2three3four4") >>> re.split("\d+","one1two2three3four4") [‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘‘] >>> re.split("\d+","4one1two2three3four4") [‘‘, ‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘‘]#如果分割時左邊或者右邊已經被分過 >>> re.split("[bc]","abcd")#或者是無字符的情況下,就分出一個空字符 [‘a‘, ‘‘, ‘d‘]
finditer():
>>> p = re.compile(r"\d+") >>> iterator = p.finditer("12 drumm44ers drumming, 11 ... 10 ...") >>> >>> iterator <callable-iterator object at 0x02626990> >>> for match in iterator: ... match.group() , match.span()#每個數字以及它們出現的位置 ... (‘12‘, (0, 2)) (‘44‘, (8, 10)) (‘11‘, (24, 26)) (‘10‘, (31, 33))
由於我們是在python下使用的正則表達式,所以特殊字符需要多次轉意,而使用了rawstring之後,就不用在多次轉意僅僅就使用正則的規則就可以。
>>> re.findall(r"\d","www4dd6") [‘4‘, ‘6‘] >>> re.findall("\\d","www4dd6") [‘4‘, ‘6‘] >>> re.findall("\d","www4dd6") [‘4‘, ‘6‘] #在這裏\d成功的原因是因為\d在ascii碼中沒有特殊含義,所以在這裏就自動轉意了,不過正規的寫法就是前兩個
單詞邊界
>>> re.findall(r"\babc","abcsd abc") [‘abc‘, ‘abc‘] >>> re.findall(r"abc\b","abcsd abc") [‘abc‘] >>> re.findall(r"abc\b","abcsd abc*") [‘abc‘] >>> re.findall(r"\babc","*abcsd*abc") [‘abc‘, ‘abc‘] #檢測單詞邊界不一定就是空格,還可以是除了字母以外的特殊字符
Python學習:13.Python正則表達式