2016-06-29 50 views
3

我有一組需要重新格式化的英國郵政編碼。它們由incode和outcode組成,其中incode的形式是'數字字母',例如2DB,並且出口碼是2和4個字母和數字的組合,例如NW1或SW10或EC1AR - 將可變數量的空格插入到郵編字符串中

目前存在incode和outcode的之間有一個空格,但我需要重新格式化這些使之充分郵政編碼爲7個字符例如:(「 - 」代表空格)

  • NW1-2DB - > NW1-2DB
  • SW10-9NH(outcode的和incode 1米之間的空間) - > 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)) 

,但得到這個錯誤:

Error: invalid 'times' argument

沒有最後一步創建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 

如果我的代表「時間」參數設置爲常數的代碼運行正常(但沒有做什麼,我需要做的!)

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()接受一列作爲參數在mutate中?或者我應該看一個完全不同的方法?

編輯:我剛剛意識到,我可以使用if語句的每個案例的2個字符,3個字符或4個字符的outcode,但不覺得很優雅。

+0

您是否必須使用正則表達式來拆分郵政編碼? 'strsplit'有什麼問題? – Psidom

+0

@Psidom默認情況下,'strsplit'也使用正則表達式 - 但問題是'strsplit'需要* something *來分割。如果你看看OP的正則表達式,你會發現中間的空間在輸入中完全是可選的。 –

+0

你說得對,'strsplit'只要incode和outcode之間有一個空格就行(正如我指定的那樣),但是Konrad是正確的,因爲postcode並不總是這樣格式化。我在這個問題上過於具體是不好的。 – lapsel

回答

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版本張貼以上,但它要求郵政編碼全部由空格隔開。根據我的經驗,通常情況並非如此。

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 
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
df%>%mutate(Postcode7=paste0(format(gsub('\\s.*$','',postcode),justify='left'), 
         format(gsub('^\\S+\\s','',postcode),justify='right'))) 
+0

該代碼通常不起作用,它要求(a)至少有一個空格分隔郵編組,並且(b)數據框至少包含一個已正確格式化的郵編;否則的理由將無法正常工作。 –

相關問題