目前在學(xué)習(xí)《基于R語言的自動(dòng)數(shù)據(jù)收集》和《用pyton寫網(wǎng)絡(luò)爬蟲》动羽,兩者都介紹網(wǎng)頁數(shù)據(jù)獲取的相關(guān)途徑,前者分析了xml镣典、json兔毙、xpath、正則表達(dá)式兄春,后者對(duì)python內(nèi)正則表達(dá)式澎剥、Beautiful Soup和Lxml三者性能比較,如下表:
今天僅僅對(duì)正則表達(dá)式知識(shí)學(xué)習(xí)整理赶舆。Web上的內(nèi)容主要是無結(jié)構(gòu)的文本哑姚。網(wǎng)絡(luò)抓取的一項(xiàng)核心任務(wù)就是從文本數(shù)據(jù)堆中采集和我們研究問題相關(guān)的信息祭饭。
正則表達(dá)式
正則表達(dá)式是用于搜索和操作文本數(shù)據(jù)的概括性文本特征。嚴(yán)格意義上叙量,與其說它們是一個(gè)工具倡蝙,不如說它們是如何通過各種函數(shù)對(duì)字符串進(jìn)行查詢的慣例。本文介紹R中實(shí)現(xiàn)擴(kuò)展正則表達(dá)式的基本組成部分宛乃。下面字符串會(huì)貫穿本文的例子:
R> example.obj <- "1. A small sentence. - 2. Another tiny sentence."
嚴(yán)格的字符匹配
最基礎(chǔ)的層次就是字符和字符的匹配悠咱,即使正則表達(dá)式也是如此。因此征炼,從一個(gè)字符串提取一個(gè)子串就會(huì)得到子串本身析既,如果有:
R> str_extract(example.obj , "small")
[1] "small"
否則,函數(shù)會(huì)返回一個(gè)缺失值:
R> str_extract(example.obj , "banana")
[1] NA
這里及其它部分使用的函數(shù)主要是來自stringr組件的str_extract(),我們假定這個(gè)組件的所有后續(xù)例子里都已加載了的谆奥。該函數(shù)的定義是str_extract(string , pattern),這樣首先輸入要被操作的字符串眼坏,然后就是要查找的表達(dá)式。該函數(shù)會(huì)在一個(gè)給定的字符串里返回與給定正則表達(dá)式匹配的第一個(gè)實(shí)例酸些。我們也可以調(diào)用str_extract_all()函數(shù)要求R取出每一個(gè)匹配的結(jié)果宰译。大家有興趣了解R和string字符串操作函數(shù)的比較,可以百度資料自行了解魄懂。
R> unlist(str_extract_all(example.obj , "sentence"))
[1] "sentence" "sentence"
由于str_extract_all()通逞爻蓿可以對(duì)多個(gè)字符串進(jìn)行調(diào)用,所以結(jié)果是作為一個(gè)列表返回的市栗,每個(gè)列表元素提供了針對(duì)其中的一個(gè)字符串的結(jié)果缀拭。上述調(diào)用中,輸入字符串是一個(gè)長度為1的字符向量填帽,因此蛛淋,函數(shù)會(huì)返回一個(gè)長度為1的列表,對(duì)它調(diào)用unlist()以便解析篡腌。下面把上述結(jié)果和同時(shí)對(duì)多個(gè)字符串進(jìn)行調(diào)用時(shí)國企函數(shù)的表現(xiàn)進(jìn)行比較褐荷。我們創(chuàng)建一個(gè)包含了"text" "manipulation" "basics"幾個(gè)字符串的向量。然后使用str_extract_all()函數(shù)來提取符合特征"a"的所有實(shí)例:
R> out <-str_extract_all(c("text","manipulation","basics") , "a")
R> out
[[1]]
character(0)
[[2]]
[1] "a" "a"
[[3]]
[1] "a"
該函數(shù)返回一個(gè)與輸入向量長度(也就是3)相同的列表嘹悼,列表每個(gè)元素包含一個(gè)字符串的結(jié)果叛甫。因?yàn)榈谝粋€(gè)字符串里沒有a,所以第一個(gè)元素是一個(gè)空字符向量杨伙。第二個(gè)字符串包含2個(gè)a合溺,第三個(gè)字符串有1個(gè)。
默認(rèn)情況下缀台,字符匹配是區(qū)分字母大小寫的。因此哮奇,正則表達(dá)式里的大寫字母和小寫字母是不一樣的膛腐。
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"
使用正則表達(dá)式并不局限于匹配的單詞怔揩。一個(gè)字符串無非是一個(gè)字符的序列。因此脯丝,我們也可以匹配字根:
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"
正則表達(dá)式的廣義化
到目前為止,我們只是進(jìn)行固定表達(dá)式的匹配宠进。但正則表達(dá)式的威力來源于能夠編寫靈活及廣義化的查詢條件晕拆。其中最為廣義化的是句號(hào)( . )。它可以匹配任意字符材蹬。
R> str_extract(example.obj , "sm.ll")
[1] "small"
在正則表達(dá)式中实幕,另一個(gè)強(qiáng)大的廣義化是字符類(character class),它被包裹在中括號(hào)里[ ]堤器。一個(gè)字符類的含義是任何中括號(hào)里的字符都會(huì)被匹配昆庇。
R> str_extract(example.obj , "sm[abc]ll")
[1] "small"
還有另一種方法也可以利用字符范圍來指定字符類的元素,它使用 - 闸溃。
R> str_extract(example.obj , "sm[a-p]ll")
[1] "small"
在這種情況下整吆,任何a到p的字符都是合法的匹配。除了字母和數(shù)字字符圈暗,也可以在正則表達(dá)式里包括標(biāo)點(diǎn)和空格掂为。相類似,它們也可以放在字符類里员串。例如勇哗,字符[uvw.]能匹配u、v寸齐、w欲诺,也能匹配句號(hào)和空格。