R - 在邮政编码字符串中插入可变数量的空格

时间:2016-06-29 16:41:06

标签: regex r dplyr postal-code

我有一套需要重新格式化的英国邮政编码。它们由incode和outcode组成,其中incode的形式为'数字字母',例如2DB和outcode是2到4个字母和数字的组合,例如NW1或SW10或EC1A

目前在incode和outcode之间有一个空格,但我需要重新格式化这些空格,以便完整的邮政编码长度为7个字符,例如:(' - '代表空格)

  • NW1-2DB - > NW1-2DB(outcode和incode之间的1个空格)
  • SW10-9NH - > SW109NH(0格)
  • E1-6QL - > E1--6QL(2个空格)

数据:

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语句,但感觉不是很优雅。

4 个答案:

答案 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')))