正則表達式模塊re
1. 正則簡介
就其本質而言,正則表達式(或 RE)是一種小型的、高度專業化的編程語言,
(在Python中)它內嵌在Python中,並通過 re 模塊實現。正則表達式模式被
編譯成一系列的字節碼,然后由用 C 編寫的匹配引擎執行。
2.正則匹配之字符匹配
- 普通子符匹配 大多數字符和字母都會和自身匹配
>>> s = "this is myblogs ,1 2 ,34" >>> re.findall('is',s) ['is', 'is'] >>> re.findall('2',s) ['2']
-
二元字符匹配
-
常用元字符:
- . 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符
- ^ 匹配起始位置
- $ 匹配終止位置
- * 匹配前面的字符0到多次,可以沒有
- + 匹配前面的字符1到多次,最少有一個
- ? 匹配前面的字符0-1次
- \ 轉義符 反斜杠后面跟元字符去除特殊功能, 反斜杠后面跟普通字母實現特殊功能
- {} 匹配次數 如 {3}匹配3次,{1,5} 匹配1到五次
- [] 或的作用 a[bc]d 匹配 abd acd ,除了
-
,非^
,"" 里面的特殊符號沒有任何意義
-
具體使用:
-
>>> s = "this is myblogs , my name is blogs" # . 表示任意字符,通用匹配 >>> re.findall('.s',s) #使用.匹配任意以s結尾的兩位字符串 ['is', 'is', 'gs', 'is', 'gs'] >>> re.findall('.blogs',s) ['yblogs', ' blogs'] >>> re.findall('b.og',s) ['blog', 'blog'] # ^ 表示匹配開頭,只匹配開頭內容 >>> re.findall('^is',s) [] >>> re.findall('^th',s) ['th'] >>> re.findall('^this',s) ['this'] # $表示匹配結尾內容,只匹配結尾,用在字符之后 >>> re.findall('$s',s) #注意$要放字符串后邊 [] >>> re.findall('s$',s) ['s'] >>> re.findall('.s$',s) ['gs'] # *表示匹配前面字符0到多次,用在字符之后,只針對前面的一個字符 >>> s = "aabbccddabcdabcd" >>> re.findall('a*',s) #匹配0到多次,所以會打印沒有匹配到的 ['aa', '', '', '', '', '', '', 'a', '', '', '', 'a', '', '', '', ''] >>> re.findall('aa*',s) #匹配第二個a出現的0到多次 ['aa', 'a', 'a'] >>> re.findall('ab*',s) #匹配b出現的0到多次 ['a', 'abb', 'ab', 'ab'] # + 匹配前面的字符1到多次,最少有一個 >>> re.findall('a+',s) #最少出現一個a ['aa', 'a', 'a'] >>> re.findall('aa+',s) #最少出現一個aa ['aa'] >>> re.findall('ab+',s) #最少出現一個ab ['abb', 'ab', 'ab'] # ? 匹配前面的字符0-1次,只能出現一次或沒有 >>> s = "aa bb cc dd abcd ababcdcd" >>> re.findall('aa?',s) ['aa', 'a', 'a', 'a'] >>> re.findall('ab?',s) ['a', 'a', 'ab', 'ab', 'ab'] #匹配出現一次b或者沒有,所結果中b只能出現一次或者沒有 # / 轉義功能,去除后面字符的特殊意義 >>> s = "* *? +> <>" >>> re.findall('^\*',s) #匹配*號 ['*'] >>> re.findall('\*.',s) ['* ', '*?'] #{} 指定匹配次數 s = "aa bb aaa bbb aabbcc aaabbb abab ababab" >>> re.findall('a{1,2}',s) #匹配a出現的1-2次,即a aa ['aa', 'aa', 'a', 'aa', 'aa', 'a', 'a', 'a', 'a', 'a', 'a'] >>> re.findall('ab{1,2}',s) #匹配ab或 abb ['abb', 'abb', 'ab', 'ab', 'ab', 'ab', 'ab'] # [] 或的作用 >>> s = "abc adc aec adec abbc addc abbbc adddc ac abbddc" >>> re.findall('a[db]c',s) #匹配abc 或adc ['abc', 'adc'] >>> re.findall('a[db]+c',s) #匹配ac中間至少1個b或d,可以有多個 ['abc', 'adc', 'abbc', 'addc', 'abbbc', 'adddc', 'abbddc'] >>> re.findall('a[db]?c',s) #匹配ac中間一個a或b,可以沒有 ['abc', 'adc', 'ac'] >>> re.findall('a[db]*c',s) #匹配ac中間0到多個b或d ['abc', 'adc', 'abbc', 'addc', 'abbbc', 'adddc', 'ac', 'abbddc'] >>> re.findall('a[^db]c',s) #匹配ac中間不出現b或d的情況 ^在這里表示非 ['aec'] >>> s = "abc abbbbbc a1231c a_+_+_+_+_+_c " >>> re.findall('a[a-z,0-9]+c',s) #匹配ac中間是字母或數字 ['abc', 'abbbbbc', 'a1231c']
-
其他特殊意義的字符加字母:
- \w 匹配包括下划線的任何單詞字符。等價於'[A-Za-z0-9_]'。
- \W 匹配任何非單詞字符。等價於 '[A-Za-z0-9_]'。
- \s 匹配任意空白字符,等價於 [\t\n\r\f].
- \S 匹配任意非空字符
- \d 匹配任意數字,等價於 [0-9].
- \D 匹配任意非數字
- \A 匹配字符串開始
- \Z 匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串。c
- \z 匹配字符串結束
- \G 匹配最后匹配完成的位置。
- \b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配
never
中的 'er',但不能匹配verb
中的 'er'。 - \B 匹配非單詞邊界。'er\B' 能匹配
verb
中的 'er',但不能匹配never
中的 'er'。 - \n, \t, 等. 匹配一個換行符。匹配一個制表符。等
- \1...\9 匹配第n個分組的子表達式。
- \10 匹配第n個分組的子表達式,如果它經匹配。否則指的是八進制字符碼的表達式。
具體實例:
>>> s = "1234 abcd ABCD _ * <>" >>> re.findall('\\w',s) ['1', '2', '3', '4', 'a', 'b', 'c', 'd', 'A', 'B', 'C', 'D', '_'] >>> re.findall('\\W',s) [' ', ' ', ' ', ' ', '*', ' ', '<', '>'] >>> re.findall('\\s',s) [' ', ' ', ' ', ' ', ' '] >>> re.findall('\\S',s) ['1', '2', '3', '4', 'a', 'b', 'c', 'd', 'A', 'B', 'C', 'D', '_', '*', '<', '>'] >>> re.findall('\\d',s) ['1', '2', '3', '4'] >>> re.findall('\\D',s) [' ', 'a', 'b', 'c', 'd', ' ', 'A', 'B', 'C', 'D', ' ', '_', ' ', '*', ' ', '<', '>'] >>> re.findall('\\A',s) [''] >>> re.findall('\\A1',s) ['1'] >>> re.findall('\\A2',s) [] >>> re.findall('\\Z\>',s) [] >>> re.findall('\>\\Z',s) ['>']
PS:
反斜杠的困擾
與大多數編程語言相同,正則表達式里使用"作為轉義字符,這就可能造成反斜杠困擾。假如你需要匹配文本中的字符
",那么使用編程語言表示的正則表達式里將需要4個反斜杠\\
:前兩個和后兩個分別用於在編程語言里轉義成反斜杠,轉換成兩個反斜杠后再在正則表達式里轉義成一個反斜杠。Python里的原生字符串很好地解決了這個問題,這個例子中的正則表達式可以使用r\
表示。同樣,匹配一個數字的\d
可以寫成r\d
。有了原生字符串,你再也不用擔心是不是漏寫了反斜杠,寫出來的表達式也更直觀。
所謂原生字符串就是python解釋器不在解釋規則在python中的含義,而是直接交給re模塊來處理
- 分組匹配
分組匹配一般使用(),被括起來的表達式將作為一組,上面所說的只是針對單個字符串,如果需要匹配多個字符串,則用到了分組匹配。先匹配成功全部正則,再匹配成功的局部內容提取出來
如下:
>>> s = "aa bb aaa bbb aabbcc aaabbb abab ababab" >>> re.findall('(ab).',s) #同時匹配ab ['ab', 'ab', 'ab', 'ab']
下面將在re模塊常用函數中來說明
3. 正則匹配方式:
- re.findall(pattern, string) 匹配字符串中所有符合規則的字符串,並以列表形式返回
注意:
findall如果使用了分組,則輸出的內容將是分組中的內容而非find到的結果,
為了得到find到的結果,要加上問號來啟用“不捕捉模式”,就可以了。
>>> re.findall("www.(baidu|xinlang)\.com","www.baidu.com") ['baidu'] >>> re.findall("www.(?:baidu|xinlang)\.com","www.baidu.com") ['www.baidu.com']
- re.match(pattern, string, flags=0) 只匹配字符串中開頭符合規則的字符串,其返回的是一個對象 pattern 是正則規則 string 是字符串 flags 是匹配模式
>>> s = '123abc4545' >>> re.match(r'\w',s) <_sre.SRE_Match object; span=(0, 1), match='1'> >>> re.match(r'\w',s).group() 只匹配字符串開頭 '1'
- re.search(pattern,string,flags=0) 匹配字符串的所有,但是匹配即停止,只返回第一個匹配的字符 pattern 是正則規則 string 是字符串 flags 是匹配模式
>>> s = '123abc4545' >>> re.search(r'\w',s) <_sre.SRE_Match object; span=(0, 1), match='1'> >>> re.search(r'\w',s).group() '1' >>> re.search(r'\D',s).group() 'a'
-
PS:以上match和search都返回的是對象,其返回的對象有以下屬性和方法:
-
屬性:
- string: 匹配時使用的文本。
- re: 匹配時使用的Pattern對象。
- pos: 文本中正則表達式開始搜索的索引。值與Pattern.match()和Pattern.seach()方法的同名參數相同。
- endpos: 文本中正則表達式結束搜索的索引。值與Pattern.match()和Pattern.seach()方法的同名參數相同。
- lastindex: 最后一個被捕獲的分組在文本中的索引。如果沒有被捕獲的分組,將為None。
- lastgroup: 最后一個被捕獲的分組的別名。如果這個分組沒有別名或者沒有被捕獲的分組,將為None。
-
方法:
- group([group1, …]): 獲得一個或多個分組截獲的字符串;指定多個參數時將以元組形式返回。group1可以使用編號也可以使用別名;編號0代表整個匹配的子串;不填寫參數時,返回group(0);沒有截獲字符串的組返回None;截獲了多次的組返回最后一次截獲的子串。
- groups([default]): 以元組形式返回全部分組截獲的字符串。相當於調用group(1,2,…last)。default表示沒有截獲字符串的組以這個值替代,默認為None。
- groupdict([default]): 返回以有別名的組的別名為鍵、以該組截獲的子串為值的字典,沒有別名的組不包含在內。default含義同上。
- start([group]): 返回指定的組截獲的子串在string中的起始索引(子串第一個字符的索引)。group默認值為0。
- end([group]): 返回指定的組截獲的子串在string中的結束索引(子串最后一個字符的索引+1)。group默認值為0。
- span([group]): 返回(start(group), end(group))。
- expand(template): 將匹配到的分組代入template中然后返回。template中可以使用\id或\g、\g引用分組,但不能使用編號0。\id與\g是等價的;但\10將被認為是第10個分組,如果你想表達\1之后是字符'0',只能使用\g0。
舉例:
-
>>> a = "123abc456" >>> re.search("([0-9]*)([a-z]*)([0-9]*)",a) <_sre.SRE_Match object; span=(0, 9), match='123abc456'> >>> re.search("([0-9]*)([a-z]*)([0-9]*)",a).group() '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(1) 列出第一個括號匹配部分,group(2) 列出第二個括號匹配部分,group(3)
列出第三個括號匹配部分。
-
其他函數
- split 使用正則分割字符串
>>> s = "a1b2c3" >>> re.split('\d',s) ['a', 'b', 'c', ''] #注意后面的空字符串,因為最后一個是數字,所以后邊就多一個空字符
- sub 替換匹配成功的指定位置字符串
>>> s = "a1b2c3" >>> re.sub('\d','-',s) 'a-b-c-'
- compile 將正則表達式編譯成Pattern對象,后面可以直接調用
>>> a = re.compile('\d') >>> s = "a1b2c3" >>> a.findall(s) ['1', '2', '3']
- finditer 搜索string,返回一個順序訪問每一個匹配結果(Match對象)的迭代器
>>> a = re.compile('\d') >>> s = "a1b2c3" >>>for m in a.finditer(s):print(m.group()) ... 1 2 3
4.常用正則匹配
- 匹配手機號
>>> s = "my name is jeck, my phone is 18611112222, my email is jeck@gmail.com,my ip is 10.20.10.20,,my ID card is 110521199012256515" >>> re.findall('(1[3578]\d{9})',s) ['18611112222'] >>> re.search('(1[3578]\d{9})',s).group() '18611112222' >>> re.search('(13[0-9]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}',s).group() '18611112222'
- 匹配身份證
s = "my name is jeck, my phone is 18611112222, my email is jeck@gmail.com,my ip is 10.20.10.20,,my ID card is 110521199012256515" >>> re.search("([1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$)",s).group() '110521199012256515'
- 匹配ip地址
s = "my name is jeck, my phone is 18611112222, my email is jeck@gmail.com,my ip is 10.20.10.20,,my ID card is 110521199012256515" >>> re.search('\d+\.\d+\.\d+\.\d+',s).group() '10.20.10.20' >>> re.search('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}',s).group() '10.20.10.20'
- 匹配郵箱
>>>s = "my name is jeck, my phone is 18611112222, my email is jeck@gmail.com,my ip is 10.20.10.20,,my ID card is 110521199012256515" >>>re.search('([a-zA-Z0-9._%+-])+@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})',s).group() 'jeck@gmail.com'