2017-02-09 17 views
7

Vì vậy, tôi có tập dữ liệu với các địa chỉ đường phố, chúng được định dạng rất khác nhau. Ví dụ:Cách chia chuỗi trên số đầu tiên chỉ

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

Từ đây tôi muốn tạo hai cột. 1. X: với địa chỉ đường phố và 2. Y: với số + mọi thứ tiếp theo. Như thế này:

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

Cho đến nay tôi đã cố gắng strsplit và sau đó một số câu hỏi tương tự ở đây, ví dụ: strsplit(d, split = "(?<=[a-zA-Z])(?=[0-9])", perl = T)). Tôi dường như không thể tìm thấy cụm từ thông dụng chính xác.

Mọi trợ giúp đều được đánh giá cao. Cảm ơn bạn trước!

Trả lời

7

Có thể có khoảng trắng giữa chữ viết và một chữ số, vì vậy thêm \s* (zero hoặc nhiều ký tự khoảng trắng) giữa 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" 

Và nếu bạn muốn tạo các cột dựa trên đó, bạn có thể tận dụng các separate từ tidyr gói:

> 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

@ Xích đạo: Có, nhưng hãy để lại cái gì đó cho OP để làm. Không có bất kỳ mã liên quan đến việc tạo khung dữ liệu nào trong câu hỏi, đó là tất cả về regex. –

+1

Cảm ơn tất cả sự giúp đỡ. Cuối cùng, tôi đã sử dụng colsplit, với regex được cung cấp và sau đó liên kết chúng với tập dữ liệu hiện có. Các hình thức giải pháp Sathish là nhiều hơn nữa thanh lịch, cảm ơn. – Jesse

3

Một cách tiếp cận phi regex sử dụng str_locate từ stringr để xác định vị trí các chữ số đầu tiên trong chuỗi và sau đó phân chia dựa trên vị trí đó, tức là

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 

LƯU Ý mà bạn nhận được một (vô hại) cảnh báo đó là kết quả của sự chia rẽ tại "Road 12 - 15" chuỗi mang đến cho [1] "Road" "12 - 15" ""

+1

cảm ơn bạn về giải pháp này – Jesse

3

này cũng sẽ làm việc:

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

cảm ơn bạn đã chỉ ra giải pháp: [[: alpha:]] và [[: digit:]]. làm cho nó dễ đọc hơn – Jesse

2

Chúng ta có thể sử dụng read.csv với sub từ 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

giải pháp thú vị! – Jesse

Các vấn đề liên quan