R - Вставка переменного количества пробелов в строку почтового индекса

У меня есть набор почтовых индексов Великобритании, которые необходимо переформатировать. Они состоят из инкода и внешнего кода, где инкод имеет форму "цифра-буква", например, 2DB, а код выхода - это комбинация из 2–4 букв и цифр, например, NW1 или SW10 или EC1A.

В настоящее время между incode и outcode есть один пробел, но мне нужно переформатировать их так, чтобы полный почтовый индекс был длиной 7 символов, например: ('-' обозначает пробел)

  • NW1-2DB -> NW1-2DB (1 пробел между исходящим кодом и incode)
  • 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() принять столбец в качестве аргумента раз в мутации? Или я должен смотреть на совершенно другой подход?

РЕДАКТИРОВАТЬ: я только что понял, что я могу использовать if утверждение для каждого случая из 2 символов, 3 символов или 4 символов в исходном коде, но это не очень элегантно.

4 ответа

Решение

Другое решение, использующее 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 версия размещена выше, но она требует, чтобы все почтовые индексы были разделены пробелами. По моему опыту это вообще не так.

Посмотрите на 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
df%>%mutate(Postcode7=paste0(format(gsub('\\s.*$','',postcode),justify='left'),
                        format(gsub('^\\S+\\s','',postcode),justify='right')))

Используя 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
Другие вопросы по тегам