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