我正在尝试使用英国政府在此处提供的正则表达式从 R 中的地址字符串中提取英国邮政编码。
这是我的功能:
address_to_postcode <- function(addresses) {
# 1. Convert addresses to upper case
addresses = toupper(addresses)
# 2. Regular expression for UK postcodes:
pcd_regex = "[Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) {0,1}[0-9][A-Za-z]{2})"
# 3. Check if a postcode is present in each address or not (return TRUE if present, else FALSE)
present <- grepl(pcd_regex, addresses)
# 4. Extract postcodes matching the regular expression for a valid UK postcode
postcodes <- regmatches(addresses, regexpr(pcd_regex, addresses))
# 5. Return NA where an address does not contain a (valid format) UK postcode
postcodes_out <- list()
postcodes_out[present] <- postcodes
postcodes_out[!present] <- NA
# 6. Return the results in a vector (should be same length as input vector)
return(do.call(c, postcodes_out))
}
根据指导文档,这个正则表达式寻找的逻辑如下:
“GIR 0AA”或一个字母后跟一个或两个数字或一个字母后跟一个必须是 ABCDEFGHJ KLMNOPQRSTUVWXY(即不是 I)之一的第二个字母,然后是一个或两个数字或一个字母后跟一个数字,然后是另一个字母或一个两部分的邮政编码,其中第一部分必须是一个字母,然后是第二个字母,该字母必须是 ABCDEFGH JKLMNOPQRSTUVWXY 之一(即不是 I),然后是一个数字,之后可以选择另一个字母AND 第二部分(与第一部分用空格分隔)必须是一个数字后跟两个字母。允许大小写字符的组合。注意:长度由正则表达式确定,介于 2 到 8 个字符之间。
^
我的问题是,当使用没有和锚的正则表达式时,这个逻辑没有完全保留$
(因为我必须在这种情况下做,因为邮政编码可以在地址字符串中的任何位置);我正在努力解决的是如何在部分(而不是完整)字符串匹配中保留每个段的字符顺序和数量。
考虑以下示例:
> address_to_postcode("1A noplace road, random city, NR1 2PK, UK")
[1] "NR1 2PK"
根据指南中的逻辑,邮政编码中的第二个字母不能是“z”(还有其他一些排除项);但是看看当我添加“z”时会发生什么:
> address_to_postcode("1A noplace road, random city, NZ1 2PK, UK")
[1] "Z1 2PK"
...而在这种情况下,我希望输出为NA
.
添加锚点(对于不同的用例)似乎没有帮助,因为即使它位于错误的位置,仍然可以接受“z”:
> grepl("^[Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) {0,1}[0-9][A-Za-z]{2})$", "NZ1 2PK")
[1] TRUE
两个问题:
- 我是否误解了正则表达式的逻辑和
- 如果不是,我该如何更正它(即为什么指定的字母和字符范围不是它们在正则表达式中的位置所独有的)?