我有一套需要重新格式化的英国邮政编码。它们由incode和outcode组成,其中incode的形式为'数字字母',例如2DB和outcode是2到4个字母和数字的组合,例如NW1或SW10或EC1A
目前在incode和outcode之间有一个空格,但我需要重新格式化这些空格,以便完整的邮政编码长度为7个字符,例如:(' - '代表空格)
数据:
df <- data.frame("postcode"=c("NW1 2DB","SW10 9NH","E1 6QL"))
df
# postcode
# 1 NW1 2DB
# 2 SW10 9NH
# 3 E1 6QL
我编写了一个正则表达式字符串来分隔outcode和incode,但找不到在它们之间添加可变数量空格的方法(这个例子只是在outcode和incode之间创建两个空格)。
require(dplyr)
df <- df %>% mutate(postcode_2sp = gsub('?(\\S+)\\s*?(\\d\\w{2})$','\\1 \\2', postcode)
为了解决这个问题,我尝试使用mutate()
,nchar()
和rep()
:
df<-df %>%
mutate(outcode=gsub('?(\\S+)\\s*\\d\\w{2}$','\\1',postcode),
incode=gsub('\\S+\\s*?(\\d\\w{2})$','\\1',postcode)) %>%
mutate(out_length=nchar(outcode))%>%
mutate(postcode7=paste0(outcode,
paste0(rep(" ",4-out_length),collapse=""),
incode))
但得到此错误:
错误:无效的'次'参数
没有创建postcode7的最后一步,df如下所示:
df
# postcode outcode incode out_length
# 1 NW1 2DB NW1 2DB 3
# 2 SW10 9NH SW10 9NH 4
# 3 E1 6QL E1 6QL 2
如果我将rep'times'参数设置为常量,则代码按预期运行(但不执行我需要它执行的操作!)
df<-df %>%
mutate(outcode=gsub('?(\\S+)\\s*\\d\\w{2}$','\\1',postcode),
incode=gsub('\\S+\\s*?(\\d\\w{2})$','\\1',postcode)) %>%
mutate(out_length=nchar(outcode))%>%
mutate(postcode7=paste0(outcode,
paste0(rep(" ",4),collapse=""),
incode))
df
# postcode outcode incode out_length postcode7
# 1 NW1 2DB NW1 2DB 3 NW1 2DB
# 2 SW10 9NH SW10 9NH 4 SW10 9NH
# 3 E1 6QL E1 6QL 2 E1 6QL
有没有办法让rep()
接受一个列作为变异中的次参数?或者我应该看一个完全不同的方法?
编辑:我刚刚意识到我可以在输出代码中为每个2个字符,3个字符或4个字符的情况使用if
语句,但感觉不是很优雅。
答案 0 :(得分:4)
请查看str_pad
包中的stringr
方法,该方法适用于您的情况:
library(stringr)
df<-df %>%
mutate(outcode=gsub('?(\\S+)\\s*\\d\\w{2}$','\\1',postcode),
incode=gsub('\\S+\\s*?(\\d\\w{2})$','\\1',postcode)) %>%
mutate(out_length=nchar(outcode)) %>%
mutate(postcode7 = paste(outcode, str_pad(incode, 7-out_length), sep = ""))
df
# postcode outcode incode out_length postcode7
# 1 NW1 2DB NW1 2DB 3 NW1 2DB
# 2 SW10 9NH SW10 9NH 4 SW109NH
# 3 E1 6QL E1 6QL 2 E1 6QL
答案 1 :(得分:2)
使用str_pad并分开:
library(dplyr)
library(tidyr)
library(stringr)
df %>%
separate(postcode, into = c("incode", "outcode"), remove = FALSE) %>%
mutate(
postcode8 = paste0(incode,
str_pad(outcode,
8 - nchar(incode), side = "left", pad = " ")))
# postcode incode outcode postcode8
# 1 NW1 2DB NW1 2DB NW1 2DB
# 2 SW10 9NH SW10 9NH SW10 9NH
# 3 E1 6QL E1 6QL E1 6QL
答案 2 :(得分:2)
另一种解决方案,使用sprintf
格式化输出,使用tidyr::extract
进行匹配。这样做的好处是可以大大简化模式和填充代码:
df %>%
extract(postcode, into = c('out', 'in'), '(\\S{2,4})\\s*(\\d\\w\\w)') %>%
mutate(postcode = sprintf('% -4s%s', out, `in`))
我喜欢上面发布的separate
版本,但它要求邮政编码全部用空格分隔。根据我的经验,情况通常并非如此。
答案 3 :(得分:2)
df%>%mutate(Postcode7=paste0(format(gsub('\\s.*$','',postcode),justify='left'),
format(gsub('^\\S+\\s','',postcode),justify='right')))