如何仅在第一个数字处拆分字符串

8

我有一个包含街道地址的数据集,它们的格式非常不同。例如:

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))。我似乎找不到正确的正则表达式。

非常感谢任何帮助。提前致谢!

4个回答

10

字母和数字之间可能有空格,因此在环视(lookaround)之间添加\s*(零个或多个空格符号):

> 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" 

如果您想基于此创建列,可以利用tidyr软件包中的separate函数:

> 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

do.call('rbind', strsplit(d, split = "(?<=[a-zA-Z])\\s*(?=[0-9])", perl = TRUE)) - Sathish
1
@Sathish:是的,但让我们留点事情给OP去做。问题本身没有任何数据框生成相关的代码,都是关于正则表达式的。 - Wiktor Stribiżew
1
感谢所有的帮助。最终我使用了colsplit,使用提供的正则表达式,然后将它们绑定到现有的数据集上。Sathish提供的解决方案更加优雅,谢谢。 - Jesse

3
一种不使用正则表达式的方法是使用stringr中的str_locate来定位字符串中的第一个数字,然后根据该位置进行分割,例如:
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" ""


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"    

2
感谢指出[[:alpha:]]和[[:digit:]]的解决方案。这使得代码更易读。 - Jesse

2
我们可以使用来自基础R的read.csvsub函数。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接