【问题标题】:R - Inserting variable number of spaces into postcode stringR - 将可变数量的空格插入邮政编码字符串
【发布时间】:2016-11-01 12:16:41
【问题描述】:

我有一组需要重新格式化的英国邮政编码。它们由一个 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))

但得到这个错误:

错误:'times' 参数无效

没有创建 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() 接受一个列作为变异中的 times 参数?还是我应该寻找一种完全不同的方法?

编辑:我刚刚意识到,对于输出代码中 2 个字符、3 个字符或 4 个字符的每种情况,我都可以使用 if 语句,但这感觉不是很优雅。

【问题讨论】:

  • 您必须使用正则表达式来拆分您的邮政编码吗? strsplit 有什么问题?
  • @Psidom 默认情况下,strsplit 也使用正则表达式——但问题是strsplit 需要something 来拆分。如果您查看 OP 的正则表达式,您会发现中间的空格在输入中完全是可选的。
  • 你是对的,strsplit 只要在 incode 和 outcode 之间有空格(正如我所指定的)就可以工作,但 Konrad 是正确的,因为邮政编码并不总是这样格式化。我的问题太具体了。
  • @KonradRudolph 好的。我正在阅读 OP 的声明,因为 目前在 incode 和 outcode 之间有一个空格。没有很仔细地看正则表达式。这是有道理的。

标签: regex r dplyr postal-code


【解决方案1】:

看看stringr 包中的str_pad 方法,它适合您的情况:

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

【讨论】:

    【解决方案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
    

    【讨论】:

      【解决方案3】:

      另一种解决方案,使用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 版本,但它要求邮政编码都用空格分隔。根据我的经验,通常情况并非如此。

      【讨论】:

        【解决方案4】:
        df%>%mutate(Postcode7=paste0(format(gsub('\\s.*$','',postcode),justify='left'),
                                format(gsub('^\\S+\\s','',postcode),justify='right')))
        

        【讨论】:

        • 此代码通常不起作用,它要求 (a) 至少有一个空格分隔邮政编码组,并且 (b) 数据框至少包含一个已正确格式化的邮政编码;否则这个理由是行不通的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-08
        • 1970-01-01
        • 1970-01-01
        • 2014-12-19
        相关资源
        最近更新 更多