使用 Python 模塊 re 實(shí)現(xiàn)解析小工具
孫 翎, 賀 皓, 和 張 晗
2011 年 4 月 12 日發(fā)布
概要
在開發(fā)過程中發(fā)現(xiàn),Python 模塊 re(Regular Expression)是一個(gè)很有價(jià)值并且非常強(qiáng)大的文本解析工具砚尽,因而想要分享一下此模塊的使用方法。
有這樣一個(gè)簡(jiǎn)單而有趣的實(shí)踐范例:對(duì)于喜歡追看美劇的年輕人,最新一集美劇的播出時(shí)間常常是一個(gè)讓人頭疼的問題,一個(gè)實(shí)時(shí)更新美劇播出時(shí)間表的小工具會(huì)很受歡迎。
本文通過以上這個(gè)實(shí)例豪嚎,描述如何抓獲 TV.com 網(wǎng)站上的文本信息,利用 Python 的 re 模塊進(jìn)行解析谈火,并將熱門美劇播出時(shí)間顯示在自己的網(wǎng)頁上侈询,希望能夠以?shī)蕵返姆绞胶芎玫慕忉?re 模塊的用法。
Python 正則表達(dá)式模塊 (re) 簡(jiǎn)介
Python 的 re 模塊(Regular Expression 正則表達(dá)式)提供各種正則表達(dá)式的匹配操作糯耍,和 Perl 腳本的正則表達(dá)式功能類似扔字,使用這一內(nèi)嵌于 Python 的語言工具,盡管不能滿足所有復(fù)雜的匹配情況温技,但足夠在絕大多數(shù)情況下能夠有效地實(shí)現(xiàn)對(duì)復(fù)雜字符串的分析并提取出相關(guān)信息革为。Python 會(huì)將正則表達(dá)式轉(zhuǎn)化為字節(jié)碼,利用 C 語言的匹配引擎進(jìn)行深度優(yōu)先的匹配舵鳞。
Python 正則表達(dá)式語法
正則表達(dá)式可以包含普通字符和特殊字符震檩,普通字符(比如數(shù)字或者字母)可以直接對(duì)目標(biāo)字符串進(jìn)行匹配,在本文中我們主要討論利用特殊字符來模糊匹配某一些字符串的方法蜓堕,比如'|'或者'('抛虏,使用這些特殊字符,正則表達(dá)式可以表示某一類的普通字符套才,或者是改變其周圍的正則表達(dá)式的含義迂猴。具體如表 2-1 所示:
表 1. 正則表達(dá)式語法 (真的是通俗易懂了~)?
關(guān)于*?, +?, ?? 這個(gè)部分的例子有些紕漏. <.*>是貪婪匹配, <.*?>是非貪婪匹配(最小匹配)
包含’ \ ’的特殊序列的意義如表 2-2:
表 2. 正則表達(dá)式特殊序列
Python re 的主要功能
Python 的 re 正則表達(dá)式模塊定義了一系列函數(shù),常量以及異常霜旧;同時(shí)错忱,正則表達(dá)式被編譯成‘ RegexObject ’實(shí)例,本身可以為不同的操作提供方法挂据。接下來簡(jiǎn)要介紹一下這些函數(shù)的功能和用法以清。
compile
re.compile(pattern[, flags])
把正則表達(dá)式的模式和標(biāo)識(shí)轉(zhuǎn)化成正則表達(dá)式對(duì)象,供 match() 和 search() 這兩個(gè)函數(shù)使用崎逃。
re 所定義的 flag 包括:
re.I 忽略大小寫
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依賴于當(dāng)前環(huán)境
re.M 多行模式
re.S 即為’ . ’并且包括換行符在內(nèi)的任意字符(’ . ’不包括換行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依賴于 Unicode 字符屬性數(shù)據(jù)庫(kù)
re.X 為了增加可讀性掷倔,忽略空格和’ # ’后面的注釋
例:以下兩種用法結(jié)果相同:
A)
compiled_pattern = re.compile(pattern)
result = compiled_pattern.match(string)
B)
result = re.match(pattern, string)
search
re.search(pattern, string[, flags])
在字符串中查找匹配正則表達(dá)式模式的位置,返回 MatchObject 的實(shí)例个绍,如果沒有找到匹配的位置勒葱,則返回 None。
對(duì)于已編譯的正則表達(dá)式對(duì)象來說(re.RegexObject)巴柿,有以下 search 的方法:
search (string[, pos[, endpos]])
若 regex 是已編譯好的正則表達(dá)式對(duì)象凛虽,regex.search(string, 0, 50) 等同于 regex.search(string[:50], 0)。
具體示例如下广恢。
>>> pattern = re.compile("a")
>>> pattern.search("abcde")???? # Match at index 0
match
re.match(pattern, string[, flags])
判斷 pattern 是否在字符串開頭位置匹配凯旋。對(duì)于 RegexObject,有:
match(string[, pos[, endpos]])
match() 函數(shù)只在字符串的開始位置嘗試匹配正則表達(dá)式,也就是只報(bào)告從位置 0 開始的匹配情況至非,而 search() 函數(shù)是掃描整個(gè)字符串來查找匹配钠署。如果想要搜索整個(gè)字符串來尋找匹配,應(yīng)當(dāng)用 search()荒椭。
split
re.split(pattern, string[, maxsplit=0, flags=0])
此功能很常用谐鼎,可以將將字符串匹配正則表達(dá)式的部分割開并返回一個(gè)列表。對(duì) RegexObject趣惠,有函數(shù):
split(string[, maxsplit=0])
例如狸棍,利用上面章節(jié)中介紹的語法:
>>> re.split('\W+', 'test, test, test.')
['test', 'test', 'test', '']
>>> re.split('(\W+)', ' test, test, test.')
[' test ', ', ', ' test ', ', ', ' test ', '.', '']
>>> re.split('\W+', ' test, test, test.', 1)
[' test ', ' test, test.']
對(duì)于一個(gè)找不到匹配的字符串而言,split 不會(huì)對(duì)其作出分割味悄,如:
>>> re.split('a*', 'hello world')
findall
re.findall(pattern, string[, flags])
在字符串中找到正則表達(dá)式所匹配的所有子串隔缀,并組成一個(gè)列表返回。同樣 RegexObject 有:
findall(string[, pos[, endpos]])
示例如下:
#get all content enclosed with [], and return a list
finditer
re.finditer(pattern, string[, flags])
和 findall 類似傍菇,在字符串中找到正則表達(dá)式所匹配的所有子串猾瘸,并組成一個(gè)迭代器返回。同樣 RegexObject 有:
finditer(string[, pos[, endpos]])
sub
re.sub(pattern, repl, string[, count, flags])
在字符串 string 中找到匹配正則表達(dá)式 pattern 的所有子串丢习,用另一個(gè)字符串 repl 進(jìn)行替換牵触。如果沒有找到匹配 pattern 的串,則返回未被修改的 string咐低。Repl 既可以是字符串也可以是一個(gè)函數(shù)揽思。對(duì)于 RegexObject 有:
sub(repl, string[, count=0])
此語法的示例有:
>>> p = re.compile( '(one|two|three)')
>>> p.sub( 'num', 'one word two words three words')
'num word num words num words'
同樣可以用以下方法,并指定 count 為 1(只替換第一個(gè)):
>>> p.sub( 'num', ' one word two words three words', count=1)
' num word two words three words'
subn
re.subn(pattern, repl, string[, count, flags])
該函數(shù)的功能和 sub() 相同见擦,但它還返回新的字符串以及替換的次數(shù)钉汗。同樣 RegexObject 有:
subn(repl, string[, count=0])
實(shí)例分析 - 使用 re 模塊實(shí)現(xiàn)美劇時(shí)間表
這一章節(jié)將描述使用 re 模塊進(jìn)行文本解析并實(shí)現(xiàn)美劇播出時(shí)間表小工具的細(xì)節(jié)。我們會(huì)引用實(shí)際的代碼片段鲤屡,解釋在實(shí)際程序中损痰,應(yīng)當(dāng)如何使用 re 模塊實(shí)現(xiàn)文本解析的功能。
需求分析
為了將我們感興趣的信息全部提取出來渲染到一個(gè)單獨(dú)的頁面上酒来,我們選取 www.tv.com 的 html 作為數(shù)據(jù)源卢未,獲取到其 HTML 文本之后用正則表達(dá)式解析并獲得相關(guān)內(nèi)容。
請(qǐng)注意用正則表達(dá)式分析 HTML 或 XML 是痛苦的堰汉。隨處可見的變化使得寫出一個(gè)通用的正則表達(dá)式變得極為困難辽社,象這樣的任務(wù)使用專用的 HTML 或 XML 解析器更為適宜 ( 如 http://www.crummy.com/software/BeautifulSoup/, 值得一提的是翘鸭,這個(gè)解析器也是用 Python RE 實(shí)現(xiàn)的 )滴铅,為了演示 Python RE 的使用,本文全部使用正則表達(dá)式處理文本就乓。
實(shí)現(xiàn)步驟
因?yàn)榇斯ぞ叩淖詈蠼Y(jié)果會(huì)被呈現(xiàn)在一個(gè)網(wǎng)頁上汉匙,它的主要功能就是從上述的 html code 中提取出我們感興趣的 element, 并按照我們自己的對(duì)內(nèi)容的選擇重新生成一個(gè)個(gè)性化過的頁面譬淳,請(qǐng)參見附件查看我們將要解析的 html 文本。
通過檢視此 html 文件盹兢,我們需要提取的 html element 只有被 head 標(biāo)簽修飾的文檔信息元素,和被 div 標(biāo)簽修飾守伸,id 值為 episode_listing 的塊級(jí)區(qū)域绎秒。
下面對(duì)實(shí)現(xiàn)這部分功能的主要代碼進(jìn)行一些分析。
以只讀方式打開所需處理文本并讀入其內(nèi)容:
fh = open("~/vampire_episode.html", "r")
fh_str = fd.read()
讀取劇集標(biāo)題尼摹,使用正則表達(dá)式匹配以“”結(jié)束的元素见芹,注意此處使用非貪婪匹配以獲取首次匹配的內(nèi)容:
title = re.findall("", fds)
查看一下變量類型和內(nèi)容:
In [74]: type(title)
Out[74]:
In [75]: print title
-------> print(title)
['The Vampire Diaries Season 2 Episode Guide on TV.com']
讀取 html 文本中 id 值為 episode_listing 的 div 元素,注意由于此元素會(huì)跨越多行蠢涝,我們?cè)谡{(diào)用 findall 函數(shù)時(shí)需要指定 re.S 標(biāo)志玄呛,同樣使用非貪婪匹配:
此時(shí)我們已經(jīng)獲取到全部所需內(nèi)容,將他們寫入另一個(gè) html 文件:
'''
部分測(cè)試用的website失效. 且簡(jiǎn)書的語法規(guī)則對(duì)程序code支持不夠好. 跳過.
需要閱讀的可以查看:https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonre/index.html
'''
小結(jié)
盡管對(duì)于 Python 正則表達(dá)式模塊(re)的語法和相關(guān)函數(shù)的描述并不全面和二,但文章以簡(jiǎn)潔的方式介紹了最常用的正則表達(dá)式語法和函數(shù)調(diào)用方法徘铝,關(guān)于更為復(fù)雜和深入的用法討論,讀者可以參考官方文檔惯吕。在之后的章節(jié)中惕它,本文直觀地通過網(wǎng)頁文本解析的實(shí)例,講解了美劇播出時(shí)間解析小工具的實(shí)現(xiàn)方法和步驟废登,希望最后的網(wǎng)站示例和演示結(jié)果能夠提供給這一模塊的功能學(xué)習(xí)提供一些有趣并有用的幫助淹魄。
相關(guān)主題
參考 Python 使用文檔中 RE 相關(guān)章節(jié)The Python Standard Library - Regular expression operations,查看 RE 語法使用細(xì)節(jié)堡距。
參看文章Regular Expressions Primer甲锡,了解更多 Python RE 的使用實(shí)例。
參看 developerWorks 中的文章可愛的 Python:Python 中的文本處理羽戒,了解使用 Python RE 進(jìn)行文本解析的實(shí)例缤沦。