使用XML包和XPath从网站上抓取地址,我有时只能获得一个字符串,其中嵌入了我想要的邮政编码。提取邮政编码很简单,但有时会出现其他五位数的字符串。
以下是df中问题的一些变体。
zips <- data.frame(id = seq(1, 5), address = c("Company, 18540 Main Ave., City, ST 12345", "Company 18540 Main Ave. City ST 12345-0000", "Company 18540 Main Ave. City State 12345", "Company, 18540 Main Ave., City, ST 12345 USA", "Company, One Main Ave Suite 18540, City, ST 12345"))
提取邮政编码(包括5位数字和加4位数字)的R语句如下所示,但它被街道号码和套件编号的虚假邮政编码欺骗(其他地址字符串可能还有其他可能性) )。
regmatches(zips$address, gregexpr("\\d{5}([-]?\\d{4})?", zips$address, perl = TRUE))
对之前的SO问题的回答表明,正则表达式将返回最后一个连续的五位数字符串。它使用负向前瞻以确保在返回一个字符串后不存在5位数字符串。&#34;
Extracting a zip code from an address string
\b\d{5}\b(?!.*\b\d{5}\b)
但是这个问题和答案涉及PHP并提供了一个带有preg_matches()的if循环`我不熟悉那些语言和工具,但这个想法可能是正确的。
我的问题:什么R代码会找到真正的邮政编码并忽略错误的相似内容?
答案 0 :(得分:3)
这是我的第一个正则表达式答案(我还在学习)所以希望我没有说错误导致你走向错误的方向。
基本上,正如你在问题中暗示的那样,这个正则表达式会查找看起来像邮政编码的最后一个字符串,后面跟着一个看起来像邮政编码的字符串
基本语法是pattern(?!.*pattern)
,只有在没有遵循{{1>}的情况下才会匹配{一个负面的前瞻断言,语法:pattern
)任何东西 (?! )
和 .*
所以我们可以用您感兴趣的内容替换模式:
pattern
即一个正好为5个字符[0-9]{5}(-[0-9]{4})?
的数字字符串[0-9]
(可以选择跟随另一个定义为连字符的组{5}
和另一个长度为4的数字字符串{{} 1}}
将所有内容与?
一起搜索匹配,(-[0-9]{4})
为我解释结果,我得到:
gregexpr
答案 1 :(得分:1)
qdapRegex
包具有rm_zip
功能:
zips <- data.frame(id = seq(1, 5),
address = c("Company, 18540 Main Ave., City, ST 12345",
"Company 18540 Main Ave. City ST 12345-0000",
"Company 18540 Main Ave. City State 12345",
"Company, 18540 Main Ave., City, ST 12345 USA",
"Company, One Main Ave Suite 18540, City, ST 12345")
)
lapply(rm_zip(zips$address, extract=TRUE), tail, 1)
## [[1]]
## [1] "12345"
##
## [[2]]
## [1] "12345-0000"
##
## [[3]]
## [1] "12345"
##
## [[4]]
## [1] "12345"
##
## [[5]]
## [1] "12345"
编辑 Per @ lawyeR的评论:
我认为你想要一些比qdapRegex
使用的字典系统更具体的正则表达式。 rm_zip
的当前实现允许进行验证,因此我不会更改它使用的正则表达式以更灵活。我也不会改变函数rm_zip
以获得额外的参数/参数,因为qdapRegex
试图具有一致的操作函数。
据说你可以使用rm_
函数创建自己的函数并提供自己的正则表达式。我使用您的评论中指定的两个参数完成了此操作:
更复杂的数据集:
zips <- data.frame(id = seq(1, 6),
address = c("Company, 18540 Main Ave., City, ST 12345",
"Company 18540 Main Ave. City ST 12345-0000",
"Company 18540 Main Ave. City State 12345",
"Company, 18540 Main Ave., City, ST 12345 USA",
"Company, One Main Ave Suite 18540m, City, ST 12345",
"company 12345678")
)
即使字符跟随拉链
,也可以抓取功能## paste together a more flexible regular expression
pat <- pastex(
"@rm_zip",
"(?<!\\d)\\d{5}(?!\\d)",
"(?<!\\d)\\d{5}-\\d{4}(?!\\d)"
)
## Create your own function that extract is set to TRUE
rm_zip2 <- rm_(pattern=pat, extract=TRUE)
rm_zip2(zips$address)
## [[1]]
## [1] "18540" "12345"
##
## [[2]]
## [1] "18540" "12345-0000"
##
## [[3]]
## [1] "18540" "12345"
##
## [[4]]
## [1] "18540" "12345"
##
## [[5]]
## [1] "18540" "12345"
##
## [[6]]
## [1] NA
仅提取5位数拉链的功能
rm_zip3 <- rm_(pattern="(?<!\\d)\\d{5}(?!\\d)", extract=TRUE)
rm_zip3(zips$address)
## [[1]]
## [1] "18540" "12345"
##
## [[2]]
## [1] "18540" "12345"
##
## [[3]]
## [1] "18540" "12345"
##
## [[4]]
## [1] "18540" "12345"
##
## [[5]]
## [1] "18540" "12345"
##
## [[6]]
## [1] NA