#r #regex
#r #регулярное выражение
Вопрос:
У меня есть этот пример фрейма данных:
address <- c("11537 W LARKSPUR RD EL MIRAGE 85335", "6702 E CPT DREYFUS SCOTTSDALE 85254", "114 S PUEBLO ST GILBERT 85233", "16981 W YOUNG ST SURPRISE 85388")
person <- c("Maria", "Jose", "Adan", "Eva")
my_address <- tibble(person, address)
Мне нужно извлечь city
из address
столбца. Город может состоять из 1 слова или 2, но они всегда находятся перед почтовым индексом, который состоит из 5 цифр.
Из фрейма данных я хотел бы получить: «ЭЛЬ МИРАЖ», «СКОТТСДЕЙЛ» и «ГИЛБЕРТ» в новом столбце:
city
Важно:
Города всегда после слова из 2 или 3 букв, например: ST, AVE, RD.
Например, из: «16981 W YOUNG ST SURPRISE 85388». Я хотел бы получить СЮРПРИЗ, который находится после «ST».
Итак, я пробовал это регулярное выражение:
my_address$city <-gsub("(.*)([a-zA-Z])([0-9]{5})(.*)", "\2", my_address$address)
Но он возвращает весь текст в столбце, а не нужные города. Кроме того, я заметил, что я не указывал ему проверять наличие 1 или 2 слов перед 5 цифрами, поэтому он будет извлекать только 1 слово?
ОБНОВЛЕНИЕ 1:
string1 <- "114 S PUEBLO ST GILBERT 85233"
sapply(stringr::str_extract_all(string1,"\w{4,}"),"[",3)
возвращает: 85233
, когда GILBERT
ожидалось.
Комментарии:
1. Почему не ДРЕЙФУС СКОТТДЕЙЛ?
2. @NelsonGon Дрейфус — АВЕНЮ, а СКОТТДЕЙЛ — Город.
3. @NelsonGon Также слова перед городом всегда имеют длину 2 или 3 («RD», «ST», «AVE». Я думаю, это могло бы помочь в регулярном выражении. Ваш ответ возвращает «MIRAGE», когда требуется «EL MIRAGE».
4. Ваши текущие требования приводят к
bp{L}{2,3}s ((?:p{L} s )?p{L} )s d{5}b
регулярному выражению, см. regex101.com/r/zHTjX6/1 .CPT
передDREYFUS
имеет длину 3 символа.5. @OmarGonzales Что
gsub
? Это должно использоваться какstr_match(my_address$address,"\b\p{L}{2,3}\s ((?:\p{L} \s )?\p{L} )\s \d{5}\b")[,2]
. Но дело не в этом. Дело в том, что ваши требования означают, что вы ожидаетеDREYFUS SCOTTSDALE
от6702 E CPT DREYFUS SCOTTSDALE 85254
. Если у вас здесь нет правила 100%, это означает, что вы не можете использовать обычный язык и решения нет. «Я хочу это» не является требованием программирования.
Ответ №1:
Это решение dplyr stringr / tidyverse основано на том факте, что вы знаете, какие слова из 2-3 букв предшествуют городу…
# vector with 2-3 letter words before a city?
v.before <- c("ST", "RD", "AVE")
#with this vector, we can build an 'or'-pattern for a regex
library( dplyr )
library( stringr )
data.frame( person, address) %>%
mutate( place = stringr::str_extract( address, paste0("(?<=", paste0(v.before, collapse = " |" ), " ).*(?= [0-9]{5})") ) ) %>%
#no match found?, then the city is the second last word from address
mutate( place = ifelse( is.na( place ), stringr::word(address, -2), place))
# person address place
# 1 Maria 11537 W LARKSPUR RD EL MIRAGE 85335 EL MIRAGE
# 2 Jose 6702 E CPT DREYFUS SCOTTSDALE 85254 SCOTTSDALE
# 3 Adan 114 S PUEBLO ST GILBERT 85233 GILBERT
# 4 Eva 16981 W YOUNG ST SURPRISE 85388 SURPRISE
Ответ №2:
Обычно предпочитают однострочные строки, хотя это кажется чрезмерно сложным и потребует еще одного шага для удаления «ST» перед «СЮРПРИЗОМ». Это было сделано здесь, предполагая, что все начинается с «ST».
library(stringr)
new_s<-unlist(str_extract_all(my_address$address,"\w{2,} \w{3,}"))
newer_s<-str_remove_all(new_s,"^\w{3}.*\D$")
newer_s<-str_remove_all(newer_s,"\s.*\d")
res<-str_remove_all(newer_s,"^ST ")
res[res==""]<-NA
my_address$city<-res[complete.cases(res)]
Результат:
my_address
# A tibble: 4 x 3
# person address city
# <chr> <chr> <chr>
#1 Maria 11537 W LARKSPUR RD EL MIRAGE 85335 EL MIRAGE
#2 Jose 6702 E CPT DREYFUS SCOTTSDALE 85254 SCOTTSDALE
#3 Peter 16981 W YOUNG ST SURPRISE 85388 SURPRISE
#4 Paul 114 S PUEBLO ST GILBERT 85233 GILBERT
Данные:
address <- c("11537 W LARKSPUR RD EL MIRAGE 85335", "6702 E CPT DREYFUS SCOTTSDALE 85254",
"16981 W YOUNG ST SURPRISE 85388","114 S PUEBLO ST GILBERT 85233")
person <- c("Maria", "Jose","Peter","Paul")
my_address <- tibble::tibble(person, address)
Комментарии:
1. Я добавил другой, менее эффективный ответ. Возможно, у кого-то другого есть более элегантное решение.
2. Отредактировано @OmarGonzales. Для будущих пользователей. Возможно, потребуется удалить несколько путей, как в принятом ответе. Я только удалил ST здесь.