在開發過程當中發現,Python 模塊 re(Regular Expression)是一個頗有價值而且很是強大的文本解析工具,於是想要分享一下此模塊的使用方法。html
有這樣一個簡單而有趣的實踐範例:對於喜歡追看美劇的年輕人,最新一集美劇的播出時間經常是一個讓人頭疼的問題,一個實時更新美劇播出時間表的小工具會很受歡迎。python
本文經過以上這個實例,描述如何抓獲 TV.com 網站上的文本信息,利用 Python 的 re 模塊進行解析,並將熱門美劇播出時間顯示在本身的網頁上,但願可以以娛樂的方式很好的解釋 re 模塊的用法。linux
Python 的 re 模塊(Regular Expression 正則表達式)提供各類正則表達式的匹配操做,和 Perl 腳本的正則表達式功能相似,使用這一內嵌於 Python 的語言工具,儘管不能知足全部複雜的匹配狀況,但足夠在絕大多數狀況下可以有效地實現對複雜字符串的分析並提取出相關信息。Python 會將正則表達式轉化爲字節碼,利用 C 語言的匹配引擎進行深度優先的匹配。正則表達式
正則表達式能夠包含普通字符和特殊字符,普通字符(好比數字或者字母)能夠直接對目標字符串進行匹配,在本文中咱們主要討論利用特殊字符來模糊匹配某一些字符串的方法,好比'|'或者'(',使用這些特殊字符,正則表達式能夠表示某一類的普通字符,或者是改變其周圍的正則表達式的含義。具體如表 2-1 所示:數據庫
包含’ \ ’的特殊序列的意義如表 2-2:express
Python 的 re 正則表達式模塊定義了一系列函數,常量以及異常;同時,正則表達式被編譯成‘ RegexObject ’實例,自己能夠爲不一樣的操做提供方法。接下來簡要介紹一下這些函數的功能和用法。網絡
compileapp
re.compile(pattern[, flags])ide
把正則表達式的模式和標識轉化成正則表達式對象,供 match() 和 search() 這兩個函數使用。函數
re 所定義的 flag 包括:
re.I 忽略大小寫
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依賴於當前環境
re.M 多行模式
re.S 即爲’ . ’而且包括換行符在內的任意字符(’ . ’不包括換行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依賴於 Unicode 字符屬性數據庫
re.X 爲了增長可讀性,忽略空格和’ # ’後面的註釋
例:如下兩種用法結果相同:
A)
1
2
|
compiled_pattern = re.compile(pattern)
result = compiled_pattern.match(string)
|
B)
1
|
result = re.match(pattern, string)
|
search
re.search(pattern, string[, flags])
在字符串中查找匹配正則表達式模式的位置,返回 MatchObject 的實例,若是沒有找到匹配的位置,則返回 None。
對於已編譯的正則表達式對象來講(re.RegexObject),有如下 search 的方法:
search (string[, pos[, endpos]])
若 regex 是已編譯好的正則表達式對象,regex.search(string, 0, 50) 等同於 regex.search(string[:50], 0)。
具體示例以下。
1
2
3
|
>>> pattern = re.compile("a")
>>> pattern.search("abcde") # Match at index 0
>>> pattern.search("abcde", 1) # No match;
|
match
re.match(pattern, string[, flags])
判斷 pattern 是否在字符串開頭位置匹配。對於 RegexObject,有:
match(string[, pos[, endpos]])
match() 函數只在字符串的開始位置嘗試匹配正則表達式,也就是隻報告從位置 0 開始的匹配狀況,而 search() 函數是掃描整個字符串來查找匹配。若是想要搜索整個字符串來尋找匹配,應當用 search()。
split
re.split(pattern, string[, maxsplit=0, flags=0])
此功能很經常使用,能夠將將字符串匹配正則表達式的部分割開並返回一個列表。對 RegexObject,有函數:
split(string[, maxsplit=0])
例如,利用上面章節中介紹的語法:
1
2
3
4
5
6
|
>>> 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.']
|
對於一個找不到匹配的字符串而言,split 不會對其做出分割,如:
1
2
|
>>> re.split('a*', 'hello world')
['hello world']
|
findall
re.findall(pattern, string[, flags])
在字符串中找到正則表達式所匹配的全部子串,並組成一個列表返回。一樣 RegexObject 有:
findall(string[, pos[, endpos]])
示例以下:
1
2
|
#get all content enclosed with [], and return a list
>>> return_list = re.findall("(\[.*?\])",string)
|
finditer
re.finditer(pattern, string[, flags])
和 findall 相似,在字符串中找到正則表達式所匹配的全部子串,並組成一個迭代器返回。一樣 RegexObject 有:
finditer(string[, pos[, endpos]])
sub
re.sub(pattern, repl, string[, count, flags])
在字符串 string 中找到匹配正則表達式 pattern 的全部子串,用另外一個字符串 repl 進行替換。若是沒有找到匹配 pattern 的串,則返回未被修改的 string。Repl 既能夠是字符串也能夠是一個函數。對於 RegexObject 有:
sub(repl, string[, count=0])
此語法的示例有:
1
2
3
|
>>> p = re.compile( '(one|two|three)')
>>> p.sub( 'num', 'one word two words three words')
'num word num words num words'
|
一樣能夠用如下方法,並指定 count 爲 1(只替換第一個):
>>> 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])
該函數的功能和 sub() 相同,但它還返回新的字符串以及替換的次數。一樣 RegexObject 有:
subn(repl, string[, count=0])
這一章節將描述使用 re 模塊進行文本解析並實現美劇播出時間表小工具的細節。咱們會引用實際的代碼片斷,解釋在實際程序中,應當如何使用 re 模塊實現文本解析的功能。
爲了將咱們感興趣的信息所有提取出來渲染到一個單獨的頁面上,咱們選取 www.tv.com 的 html 做爲數據源,獲取到其 HTML 文本以後用正則表達式解析並得到相關內容。
請注意用正則表達式分析 HTML 或 XML 是痛苦的。隨處可見的變化使得寫出一個通用的正則表達式變得極爲困難,象這樣的任務使用專用的 HTML 或 XML 解析器更爲適宜 ( 如 http://www.crummy.com/software/BeautifulSoup/, 值得一提的是,這個解析器也是用 Python RE 實現的 ),爲了演示 Python RE 的使用,本文所有使用正則表達式處理文本。
由於此工具的最後結果會被呈如今一個網頁上,它的主要功能就是從上述的 html code 中提取出咱們感興趣的 element, 並按照咱們本身的對內容的選擇從新生成一個個性化過的頁面,請參見附件查看咱們將要解析的 html 文本。
經過檢視此 html 文件,咱們須要提取的 html element 只有被 head 標籤修飾的文檔信息元素,和被 div 標籤修飾,id 值爲 episode_listing 的塊級區域。
下面對實現這部分功能的主要代碼進行一些分析。
以只讀方式打開所需處理文本並讀入其內容:
1
2
|
fh = open("~/vampire_episode.html", "r")
fh_str = fd.read()
|
讀取劇集標題,使用正則表達式匹配以「<title」起始,「/title>」結束的元素,注意此處使用非貪婪匹配以獲取首次匹配的內容:
1
|
title = re.findall("<
title.
*?\/title>", fds)
|
查看一下變量類型和內容:
1
2
3
4
5
6
7
|
In [74]: type(title)
Out[74]: <
type
'list'>
In [75]: print title
-------> print(title)
['<
title
>The Vampire Diaries Season 2 Episode Guide on TV.com</
title
>']
|
讀取 html 文本中 id 值爲 episode_listing 的 div 元素,注意因爲此元素會跨越多行,咱們在調用 findall 函數時須要指定 re.S 標誌,一樣使用非貪婪匹配:
fd_result = re.findall("<div id=\"episode_listing\".*?\/div>", fh_str, re.S)
此時咱們已經獲取到所有所需內容,將他們寫入另外一個 html 文件:
1
2
3
4
5
6
7
|
output = open("parse_result.html", "w")
output.write('<
html
><
body
><
h1
>The Air Date List you want to see:</
h1
>')
output.write('<
br
/>')
output.write(title[0])
output.write(fd_result[0])
output.write("</
body
></
html
>")
output.close()
|
本章節將演示實例效果,展現最終能夠顯示在網頁上的運行結果,咱們將看到解析得到的美劇時間表,劇集標題等。爲此咱們在 Google App Engine 上建立了一個 Demo 示例以更好的對此本文所介紹的內容進行演示,讀者能夠直接訪問使用。示例的網址以下:
下面咱們用截圖來講明該示例的內容。該示例主要展現了對給定的包含美劇信息的 URL 所截取出來的劇集播放信息,以下圖所示本示例展現以下三部美劇的信息:
其輸出結果以下:
另外,咱們還爲讀者提供了親自體驗的 Play Ground,讀者能夠經過點擊主頁面最下方的相關連接(http://omtvdw.appspot.com/pg)來到以下界面:
在此界面裏,讀者能夠自行輸入含有美劇播出信息的相關頁面的連接,而後查看輸出結果。例如咱們輸入 http://www.tv.com/24/show/3866/episode.html?shv=list&season=5,而後點擊「Get Air Date List」就會看到關於 24 小時第五季的播出信息:
讀者能夠自行試驗獲取其餘美劇的信息,可是須要本身從 www.tv.com 上找到相似的 URL。
儘管對於 Python 正則表達式模塊(re)的語法和相關函數的描述並不全面,但文章以簡潔的方式介紹了最經常使用的正則表達式語法和函數調用方法,關於更爲複雜和深刻的用法討論,讀者能夠參考官方文檔。在以後的章節中,本文直觀地經過網頁文本解析的實例,講解了美劇播出時間解析小工具的實現方法和步驟,但願最後的網站示例和演示結果可以提供給這一模塊的功能學習提供一些有趣並有用的幫助。