【问题标题】:How to split a string on first number only如何仅在第一个数字上拆分字符串
【发布时间】:2017-02-09 10:18:13
【问题描述】:

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

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 = "(?&lt;=[a-zA-Z])(?=[0-9])", perl = T))。我似乎无法找到正确的正则表达式。

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

【问题讨论】:

    标签: r regex strsplit


    【解决方案1】:

    字母和数字之间可能有空格,因此在环视之间添加\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 = "(?&lt;=[a-zA-Z])\\s*(?=[0-9])", perl = TRUE))
    • @Sathish:是的,但是让我们为 OP 做一些事情。问题本身没有任何与数据框生成相关的代码,都是关于正则表达式的。
    • 感谢所有帮助。最后,我使用了 colsplit,提供了正则表达式,然后将它们绑定到现有数据集。 Sathish 的解决方案更加优雅,谢谢。
    【解决方案2】:

    这也可以:

    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"    
    

    【讨论】:

    • 感谢您指出:[[:alpha:]] 和 [[:digit:]] 解决方案。使其更具可读性
    【解决方案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" ""

    【讨论】:

      【解决方案4】:

      我们可以使用read.csvsub 来自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
      

      【讨论】:

      • 有趣的解决方案!
      猜你喜欢
      • 2013-08-30
      • 2017-12-15
      • 2011-06-04
      • 1970-01-01
      • 2011-05-07
      • 2017-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多