正則表示式(二)——進階之匹配分組
這部分我將換種形式來講述,結合實際問題需求來講述。
3.匹配分組
字元 | 功能 |
| | 匹配左右任意一個表示式 |
(ab) | 將括號中的字元作為一個分組 |
\num | 引用分組num匹配到的字串 |
(?P<name>) | 分組起別名 |
(?P=name) | 引用別名為name分組匹配到的字串 |
1)|
需求:匹配出0-100之間的數字
分析:首先我們明確這之間的數字包含0,兩位數,100,,也就是一位,兩位,三位的可能都有,鑑於一位0,三位100都是單獨數字,我們可以使用 | 來連線(相當於or),著重考慮一位數[1-9],兩位數[10-99],分析其特徵,這裡第一位數必須為[1-9],第二位[0-9]都可以(\d可以表示),對於一位數[1-9]的第二位可以不出現(?可以表示),再加個結尾$,防止234匹配到23的情況。因此正則表示式為:
r'[1-9]\d?$|0$|100$'
>>> re.match(r'[1-9]\d?$|0$|100$','08') None >>> re.match(r'[1-9]\d?$|0$|100$','0') <_sre.SRE_Match object; span=(0, 1), match='0'> >>> re.match(r'[1-9]\d?$|0$|100$','100') <_sre.SRE_Match object; span=(0, 3), match='100'> >>> re.match(r'[1-9]\d?$|0$|100$','101') None >>> re.match(r'[1-9]\d?$|0$|100$','80') <_sre.SRE_Match object; span=(0, 2), match='80'>
我們再看下0能不能不用 | ,也把它包含進去?答案of course。想想 0 ,它是[1-9]不出現,第二位\d也不出現的情況,因此第一位[1-9]選擇性出現用 ? ,因此正則表示式為:
r'[1-9]?\d?$|100$'
>>> re.match(r'[1-9]?\d?$|100$','0') <_sre.SRE_Match object; span=(0, 1), match='0'>
這樣的話,| 的功能是不是清楚了......
2)(ab) 將括號中的字元作為一個分組
需求 :在網頁開發或者爬蟲時,處理物件是HTML,比如某網頁HTML中有這樣的內容:<h1>我的CSDN</h1>。那麼我該如何把<h1>content</h1>中的content提取出來呢?
分析:提取的內容用()括起來就可以了。<h1> </h1>是固定標籤,這是不變的,變的是content,因此我的正則表示式可表示為:
r'<h1>(.*)</h1>'
>>> re.match(r'<h1>(.*)</h1>','<h1>我的CSDN</h1>') <_sre.SRE_Match object; span=(0, 15), match='<h1>我的CSDN</h1>'>
可以完美的匹配到了,問題還沒解決,我怎麼提取出來content呢。其實group()函式是可以接受引數的,其引數的意義是你的()個數的索引,比如你輸入reslut.group(1)得到的是第一個括號的內容。reslut.group(0)是匹配到的所有內容,預設為0,所以你不輸入,預設為0,返回匹配內容。Match Object還有個groups()函式,它返回的是所有括號的內容。如下所示:
>>> result = re.match(r'<h1>(.*)</h1>','<h1>我的CSDN</h1>') #變數儲存 >>> result.group() #預設0,返回匹配內容 '<h1>我的CSDN</h1>' >>> result.group(0) #輸入0,返回匹配內容 '<h1>我的CSDN</h1>' >>> result.group(1) #返回第1個括號內容 '我的CSDN' >>> result.groups() ('我的CSDN',)
我們看看兩個括號的情況:
>>> result = re.match(r'<span>(\d+)</span><h1>(.*)</h1>','<span>1234</span><h1>我的CSDN</h1>') >>> result <_sre.SRE_Match object; span=(0, 32), match='<span>1234</span><h1>我的CSDN</h1>'> >>> result.group(1) '1234' >>> result.group(2) '我的CSDN' >>> result.groups() ('1234', '我的CSDN')
所以說,()在網頁開發,爬蟲裡還是挺重要的......學會它
3)\num 引用分組num匹配到的字串
需求 :還是以網頁為例,比如判斷某網頁HTML格式是否正確,其中有內容:<html><h1>我的CSDN</h1></html>。這時,我們不關心裡面的內容,我們關心的是格式是否正確,就是說這樣的格式:<html>標籤必須有</html>結束,<h1>標籤必須有</h1>結束。
分析:這個時候像html和h1才是關鍵內容,如果我們把這些用()儲存起來,並且在後面一定對應這些內容,就能保證標籤的配對,而\num就是解決這樣的問題的,上面group裡面的引數index指的是第index個括號內容,\index即取得它的內容
1. 首先我們看個錯誤的樣例:
>>> s = '<html><h1>my csdn</h1></html>' >>> re.match(r'<.+><.+>.+</.+></.+>',s) #關注html和h1這些內容, .+ 表示至少有內容 <_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>'> >>> s = '<html><h1>my csdn</h1></h>' '''把s後面的html改成h,明顯格式不對,但還是匹配了''' >>> re.match(r'<.+><.+>.+</.+></.+>',s) <_sre.SRE_Match object; span=(0, 26), match='<html><h1>my csdn</h1></h>'>
我們應該讓第一個<tag>的內容出現在最後</tag>中,因此需要儲存起來,用()括起來
2.正確的方法
我們應該把<tag>用()括起來,變成<(tag)>,因此正則表示式為:
r'<(.+)><(.+)>.+</\2></\1>'
解釋下,這個\2 和 \1。這個就是我們上面groups()中的內容索引,可以拿到內容
>>> s = '<html><h1>my csdn</h1></h>' #錯誤的標籤格式 >>> re.match(r'<(.+)><(.+)>.+</\2></\1>',s) #此時不符合了 None >>> s = '<html><h1>my csdn</h1></html>' #正確的標籤格式 >>> result = re.match(r'<(.+)><(.+)>.+</\2></\1>',s) >>> result <_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>'> >>> result.groups() #那麼 \2 指的是'h1' ; \1 指的是'html' ('html', 'h1')
4)(?P<name>) 分組起別名 和 (?P=name) 引用別名
需求 :上面我們已經可以通過\num取得對應的內容用以限定前面的內容,但是如果我有100個括號,那我們就只能數括號的索引index,然後把用\index取得麼?答案:當然不是。
分析:這時候取別名(?P<name>)就派上用場了,它通過對括號裡的內容取別名,然後通過(?P=name)就可以取得對應的內容,你只要記住別名name,這樣就不用去數括號,記索引了。是不是很人性化......
這個語法是:在括號裡面同時寫上取的別名,以<>命名;引用時以=取得別名,所以該正則表示式為:
r'<(?P<key1>.+)><(?P<key2>.+)>.+</(?P=key2)></(?P=key1)>'
>>> s = '<html><h1>my csdn</h1></h>' #不正確的格式 >>> result = re.match(r'<(?P<key1>.+)><(?P<key2>.+)>.+</(?P=key2)></(?P=key1)>',s) None >>> s = '<html><h1>my csdn</h1></html>' #正確的格式 >>> result = re.match(r'<(?P<key1>.+)><(?P<key2>.+)>.+</(?P=key2)></(?P=key1)>',s) >>> result <_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>'> >>> result.groups() ('html', 'h1')
當然此時,你使用\num也是可以的,記住:(?P<name>)只是起了個別名,系統儲存了別名,你不用也沒關係,\num還是可以用的。看下圖,還是可以用\1來表示第一個內容。
>>> s = '<html><h1>my csdn</h1></html>' >>> result = re.match(r'<(?P<key1>.+)><(?P<key2>.+)>.+</(?P=key2)></\1>',s) >>> result <_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>'>
先放個表格:
函式 | 描述 |
---|---|
compile(pattern,flags= 0) | 使用任何可選的標記來編譯正則表示式的模式,然後返回一個正則表示式物件 |
match(pattern,string,flags=0) | 嘗試使用帶有可選的標記的正則表示式的模式來匹配字串。如果匹配成功,就返回匹配物件; 如果失敗,就返回 None |
search(pattern,string,flags=0) | 使用可選標記搜尋字串中第一次出現的正則表示式模式。 如果匹配成功,則返回匹配物件; 如果失敗,則返回 None |
findall(pattern,string[, flags] ) | 查詢字串中所有(非重複)出現的正則表示式模式,並返回一個匹配列表 |
finditer(pattern,string[, flags] ) | 與 findall()函式相同,但返回的不是一個列表,而是一個迭代器。 對於每一次匹配,迭代器都返回一個匹配物件 |
split(pattern,string,max=0) | 根據正則表示式的模式分隔符, split函式將字串分割為列表,然後返回成功匹配的列表,分隔最多操作 max 次(預設分割所有匹配成功的位置) |
sub(pattern,repl,string,count=0) | 使用 repl 替換所有正則表示式的模式在字串中出現的位置,除非定義 count, 否則就將替換所有出現的位置( 另見 subn()函式,該函式返回替換操作的數目) |
purge() | 清除隱式編譯的正則表示式模式 |