2017-02-09 16 views
7

Итак, у меня есть набор данных с уличными адресами, они отформатированы очень по-разному. Например:Как разбить строку только на первый номер

d <- c("street1234", "Street 423", "Long Street 12-14", "Road 18A", "Road 12 - 15", "Road 1/2") 

Из этого я хочу создать две колонки. 1. X: с адресом улицы и 2. Y: с номером + все, что следует. Как это:

X   Y 
Street  1234 
Street  423 
Long Street 12-14 
Road  18A 
Road  12 - 15 
Road  1/2 

До сих пор я пытался strsplit и последовали некоторые подобные вопросы здесь, например: strsplit(d, split = "(?<=[a-zA-Z])(?=[0-9])", perl = T)). Я просто не могу найти правильное регулярное выражение.

Любая помощь очень ценится. Заранее спасибо!

ответ

7

Там могут быть пробелы между буквой и цифрой, поэтому добавьте \s* (ноль или более пробельных символов) между lookarounds:

> strsplit(d, split = "(?<=[a-zA-Z])\\s*(?=[0-9])", perl = TRUE) 
[[1]] 
[1] "street" "1234" 

[[2]] 
[1] "Street" "423" 

[[3]] 
[1] "Long Street" "12-14"  

[[4]] 
[1] "Road" "18A" 

[[5]] 
[1] "Road" "12 - 15" 

[[6]] 
[1] "Road" "1/2" 

И если вы хотите создать столбцы, основанные на том, что, возможно, кредитное плечо separateот tidyr пакет:

> library(tidyr) 
> separate(data.frame(A = d), col = "A" , into = c("X", "Y"), sep = "(?<=[a-zA-Z])\\s*(?=[0-9])") 
      X  Y 
1  street 1234 
2  Street  423 
3 Long Street 12-14 
4  Road  18A 
5  Road 12 - 15 
6  Road  1/2 
+0

'do.call ('rbind', strsplit (d, split =" (? <= [A-zA-Z]) \\ s * (? = [0-9]) ", perl = TRUE)) ' – Sathish

+1

@Sathish: Да, но давайте оставим что-то для OP. В самом вопросе нет никакого кода генерации кадра данных, это все о регулярном выражении. –

+1

Спасибо за помощь. В конце я использовал colsplit с предоставленным регулярным выражением, а затем привязал их к существующему набору данных. Спасибо, Sathish. – Jesse

3

не-регулярное выражение подход с использованием str_locate от stringr найти первую цифру в строка, а затем разделение основано на том месте, т.е.

library(stringr) 

ind <- str_locate(d, '[0-9]+')[,1] 
setNames(data.frame(do.call(rbind, Map(function(x, y) 
      trimws(substring(x, seq(1, nchar(x), y-1), seq(y-1, nchar(x), nchar(x)-y+1))), 
                  d, ind)))[,1:2]), c('X', 'Y')) 

#   X  Y 
#1  street 1234 
#2  Street  423 
#3 Long Street 12-14 
#4  Road  18A 
#5  Road 12 - 15 
#6  Road  1/2 

ПРИМЕЧАНИЕ, что вы получите (безвредный) предупреждение, которое является результатом раскола на "Road 12 - 15" строку, которая дает [1] "Road" "12 - 15" ""

+1

спасибо за это решение – Jesse

3

Это также будет работать:

do.call(rbind,strsplit(sub('([[:alpha:]]+)\\s*([[:digit:]]+)', '\\1$\\2', d), split='\\$')) 
#  [,1]   [,2]  
#[1,] "street"  "1234" 
#[2,] "Street"  "423"  
#[3,] "Long Street" "12-14" 
#[4,] "Road"  "18A"  
#[5,] "Road"  "12 - 15" 
#[6,] "Road"  "1/2"  
+1

спасибо за то, что вы выбрали: [[: alpha:]] и [[: digit:]] решение. делает его более читаемым – Jesse

2

Мы можем использовать read.csv с sub из base R

read.csv(text=sub("^([A-Za-z ]+)\\s*([0-9]+.*)", "\\1,\\2", d), 
     header=FALSE, col.names = c("X", "Y"), stringsAsFactors=FALSE) 
#    X  Y 
#1  street 1234 
#2  Street  423 
#3 Long Street 12-14 
#4  Road  18A 
#5  Road 12 - 15 
#6  Road  1/2 
+1

интересное решение! – Jesse