【问题标题】:String split on a number word pattern在数字单词模式上拆分字符串
【发布时间】:2015-12-21 02:00:35
【问题描述】:

我有一个如下所示的数据框:

V1                        V2
peanut butter sandwich    2 slices of bread 1 tablespoon peanut butter

我的目标是:

V1                        V2
peanut butter sandwich    2 slices of bread
peanut butter sandwich    1 tablespoon peanut butter

我尝试使用strsplit(df$v2, " ") 分割字符串,但我只能使用" " 分割字符串。我不确定您是否可以仅在第一个数字处拆分字符串,然后将字符提取到下一个数字。

【问题讨论】:

    标签: regex r string split strsplit


    【解决方案1】:

    您可以按如下方式拆分字符串:

    txt <- "2 slices of bread 1 tablespoon peanut butter"
    
    strsplit(txt, " (?=\\d)", perl=TRUE)[[1]]
    #[1] "2 slices of bread"          "1 tablespoon peanut butter"
    

    这里使用的正则表达式是寻找后跟一个数字的空格。它使用零宽度正向预测 (?=) 来表示如果空格后面跟着一个数字 (\\d),那么它就是我们想要分割的空格类型。为什么是零宽度前瞻?这是因为我们不想将数字用作分割字符,我们只想匹配任何后面跟着数字的空格。

    要使用该想法并构建您的数据框,请参阅以下示例:

    item <- c("peanut butter sandwich", "onion carrot mix", "hash browns")
    txt <- c("2 slices of bread 1 tablespoon peanut butter", "1 onion 3 carrots", "potato")
    df <- data.frame(item, txt, stringsAsFactors=FALSE)
    
    # thanks to Ananda for recommending setNames
    split.strings <- setNames(strsplit(df$txt, " (?=\\d)", perl=TRUE), df$item) 
    # alternately: 
    #split.strings <- strsplit(df$txt, " (?=\\d)", perl=TRUE)
    #names(split.strings) <- df$item
    
    stack(split.strings)
    #                      values                    ind
    #1          2 slices of bread peanut butter sandwich
    #2 1 tablespoon peanut butter peanut butter sandwich
    #3                    1 onion       onion carrot mix
    #4                  3 carrots       onion carrot mix
    #5                     potato            hash browns
    

    【讨论】:

    • 简要说明 (?=) 的作用可能是值得的,因为 OP 似乎是文本操作和正则表达式的新手。
    • 很好地使用了stack。您可以使用setNames 缩短方法。 +1
    • 而且,对于管道痴迷者:library(dplyr); library(tidyr); df %&gt;% mutate(txt = strsplit(txt, " (?=\\d)", perl=TRUE)) %&gt;% unnest(txt)....
    • 感谢 Jota 和 Ananda。我也喜欢管道添加!
    【解决方案2】:

    假设你正在处理类似的事情:

    mydf <- data.frame(
      V1 = c("peanut butter sandwich", "peanut butter and jam sandwich"), 
      V2 = c("2 slices of bread 1 tablespoon peanut butter", 
             "2 slices of bread 1 tablespoon peanut butter 1 tablespoon jam"))  
    
    mydf
    ##                               V1
    ## 1         peanut butter sandwich
    ## 2 peanut butter and jam sandwich
    ##                                                              V2
    ## 1                  2 slices of bread 1 tablespoon peanut butter
    ## 2 2 slices of bread 1 tablespoon peanut butter 1 tablespoon jam
    

    您可以先在“V2”中添加一个您不希望出现的分隔符,然后使用我的“splitstackshape”中的cSplit 来获取“长”数据集格式。

    library(splitstackshape)
    mydf$V2 <- gsub(" (\\d+)", "|\\1", mydf$V2)
    cSplit(mydf, "V2", "|", "long")
    ##                                V1                         V2
    ## 1:         peanut butter sandwich          2 slices of bread
    ## 2:         peanut butter sandwich 1 tablespoon peanut butter
    ## 3: peanut butter and jam sandwich          2 slices of bread
    ## 4: peanut butter and jam sandwich 1 tablespoon peanut butter
    ## 5: peanut butter and jam sandwich           1 tablespoon jam
    

    以下内容不足以单独发布作为答案,因为它们是@Jota 方法的变体,但为了完整起见,我在这里分享它们:

    strsplit 在“data.table”中

    list 的拆分会自动平展为单列....

    library(data.table)
    as.data.table(mydf)[, list(
      V2 = unlist(strsplit(as.character(V2), '\\s(?=\\d)', perl=TRUE))), by = V1]
    

    “dplyr”+“tidyr”

    您可以使用“tidyr”中的unnest 将列表列展开为长格式....

    library(dplyr)
    library(tidyr)
    mydf %>% 
      mutate(V2 = strsplit(as.character(V2), " (?=\\d)", perl=TRUE)) %>% 
      unnest(V2)
    

    【讨论】:

      猜你喜欢
      • 2011-04-15
      • 2018-06-15
      • 1970-01-01
      • 2018-09-07
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      相关资源
      最近更新 更多