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" 或一个字母后面跟着一个或两个数字 或 一个字母后面跟着第二个字母,该字母必须是 ABCDEFGHJKLMNOPQRSTUVWXY 中的一个(即不是 I),然后跟着一个或两个数字 或 一个字母后面跟着一个数字,再跟着另一个字母 或 第一部分必须是一个字母后面跟着第二个字母,该字母必须是 ABCDEFGH JKLMNOPQRSTUVWXY 中的一个(即不是 I),然后跟着一个数字和可选的另一个字母;第二部分(与第一部分用空格隔开)必须是一个数字后面跟着两个字母。允许使用大写和小写字符组合。注意:长度由正则表达式确定,介于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
两个问题:
- 我是否误解了正则表达式的逻辑
- 如果没有,我该如何纠正它(即为什么指定的字母和字符范围不是在正则表达式中的独特位置)?