目前在學(xué)習(xí)《基于R語言的自動數(shù)據(jù)收集》和《用pyton寫網(wǎng)絡(luò)爬蟲》,兩者都介紹網(wǎng)頁數(shù)據(jù)獲取的相關(guān)途徑,前者分析了xml、json、xpath、正則表達式,后者對python內(nèi)正則表達式、Beautiful Soup和Lxml三者性能比較,如下表:

今天僅僅對正則表達式知識學(xué)習(xí)整理。Web上的內(nèi)容主要是無結(jié)構(gòu)的文本。網(wǎng)絡(luò)抓取的一項核心任務(wù)就是從文本數(shù)據(jù)堆中采集和我們研究問題相關(guān)的信息。
正則表達式
正則表達式是用于搜索和操作文本數(shù)據(jù)的概括性文本特征。嚴(yán)格意義上,與其說它們是一個工具,不如說它們是如何通過各種函數(shù)對字符串進行查詢的慣例。本文介紹R中實現(xiàn)擴展正則表達式的基本組成部分。下面字符串會貫穿本文的例子:
R> example.obj <- "1. A small sentence. - 2. Another tiny sentence."
嚴(yán)格的字符匹配
最基礎(chǔ)的層次就是字符和字符的匹配,即使正則表達式也是如此。因此,從一個字符串提取一個子串就會得到子串本身,如果有:
R> str_extract(example.obj , "small")
[1] "small"
否則,函數(shù)會返回一個缺失值:
R> str_extract(example.obj , "banana")
[1] NA
這里及其它部分使用的函數(shù)主要是來自stringr組件的str_extract(),我們假定這個組件的所有后續(xù)例子里都已加載了的。該函數(shù)的定義是str_extract(string , pattern),這樣首先輸入要被操作的字符串,然后就是要查找的表達式。該函數(shù)會在一個給定的字符串里返回與給定正則表達式匹配的第一個實例。我們也可以調(diào)用str_extract_all()函數(shù)要求R取出每一個匹配的結(jié)果。大家有興趣了解R和string字符串操作函數(shù)的比較,可以百度資料自行了解。
R> unlist(str_extract_all(example.obj , "sentence"))
[1] "sentence" "sentence"
由于str_extract_all()通??梢詫Χ鄠€字符串進行調(diào)用,所以結(jié)果是作為一個列表返回的,每個列表元素提供了針對其中的一個字符串的結(jié)果。上述調(diào)用中,輸入字符串是一個長度為1的字符向量,因此,函數(shù)會返回一個長度為1的列表,對它調(diào)用unlist()以便解析。下面把上述結(jié)果和同時對多個字符串進行調(diào)用時國企函數(shù)的表現(xiàn)進行比較。我們創(chuàng)建一個包含了"text" "manipulation" "basics"幾個字符串的向量。然后使用str_extract_all()函數(shù)來提取符合特征"a"的所有實例:
R> out <-str_extract_all(c("text","manipulation","basics") , "a")
R> out
[[1]]
character(0)
[[2]]
[1] "a" "a"
[[3]]
[1] "a"
該函數(shù)返回一個與輸入向量長度(也就是3)相同的列表,列表每個元素包含一個字符串的結(jié)果。因為第一個字符串里沒有a,所以第一個元素是一個空字符向量。第二個字符串包含2個a,第三個字符串有1個。
默認(rèn)情況下,字符匹配是區(qū)分字母大小寫的。因此,正則表達式里的大寫字母和小寫字母是不一樣的。
R> str_extract(example.obj , "small")
[1] "small"
在上面的字符串里包含small,而沒有SMALL。
R> str_extract(example.obj , "SMALL")
[1] NA
結(jié)果,該函數(shù)提取不到匹配的值。我們可以用ignore.case()包裹該字符串,從而改變這種結(jié)果。
R> str_extract(example.obj , ignore.case("SMALL"))
[1] "small"
使用正則表達式并不局限于匹配的單詞。一個字符串無非是一個字符的序列。因此,我們也可以匹配字根:
R> unlist(str_extract_all(example.obj , "en"))
[1] "en" "en" "en" "en"
或字母字符和空格的混合。
R> unlist(str_extract_all(example.obj , "mall sent"))
[1] "mall sent"
正則表達式的廣義化
到目前為止,我們只是進行固定表達式的匹配。但正則表達式的威力來源于能夠編寫靈活及廣義化的查詢條件。其中最為廣義化的是句號( . )。它可以匹配任意字符。
R> str_extract(example.obj , "sm.ll")
[1] "small"
在正則表達式中,另一個強大的廣義化是字符類(character class),它被包裹在中括號里[ ]。一個字符類的含義是任何中括號里的字符都會被匹配。
R> str_extract(example.obj , "sm[abc]ll")
[1] "small"
還有另一種方法也可以利用字符范圍來指定字符類的元素,它使用 - 。
R> str_extract(example.obj , "sm[a-p]ll")
[1] "small"
在這種情況下,任何a到p的字符都是合法的匹配。除了字母和數(shù)字字符,也可以在正則表達式里包括標(biāo)點和空格。相類似,它們也可以放在字符類里。例如,字符[uvw.]能匹配u、v、w,也能匹配句號和空格。