【问题标题】:split string last delimiter拆分字符串最后一个分隔符
【发布时间】:2017-04-23 01:24:41
【问题描述】:

当我在 R 中有不同数量的相同分隔符时,我需要帮助确定如何根据最后一个分隔符拆分数据框列中的字符串。例如,

col1 <- c('a', 'b', 'c')
col2 <- c('a_b', 'a_b_c', 'a_b_c_d')
df <- data.frame(cbind(col1, col2))

我想将 df$col2 拆分为如下所示的数据框:

col1 <- c('a', 'b', 'c')
col2 <- c('a', 'a_b', 'a_b_c')
col3 <- c('b', 'c', 'd')

【问题讨论】:

  • 顺便说一句,除非您希望自己的生活变得艰难,否则永远不要使用data.frame(cbind(...。这首先创建一个矩阵,然后是一个 data.frame 并将所有内容更改为一种类型(例如数字到字符)。只需data.frame(... 即可。
  • 谢谢@thelatemail。我显然在学习,所以每条建议都有帮助。
  • 这些人都没有一个很好的答案。

标签: r string split delimiter


【解决方案1】:

这些不使用任何包。他们假设col2 的每个元素至少有一个下划线。 (如果需要解除此限制,请参阅注释。)

1) 第一个正则表达式(.*)_ 匹配直到最后一个下划线的所有内容,然后是剩余的所有内容.*,第一个sub 用括号内的匹配部分替换整个匹配项。这是有效的,因为这样的匹配是贪婪的,所以第一个 .* 将采取一切它可以把剩下的留给第二个 .* 。第二个正则表达式匹配直到最后一个下划线的所有内容,第二个 sub 将其替换为空字符串。

transform(df, col2 = sub("(.*)_.*", "\\1", col2), col3 = sub(".*_", "", col2))

2) 这是一个更加对称的变体。它对两个sub 调用使用相同的正则表达式。

pat <- "(.*)_(.*)"
transform(df, col2 = sub(pat, "\\1", col2), col3 = sub(pat, "\\2", col2))

注意:如果我们确实想要处理完全没有下划线的字符串,以便将“xyz”拆分为“xyz”和“”,那么将其用于第二个sub。它试图匹配 | 的左侧首先,如果失败(如果没有下划线会发生这种情况),那么整个字符串将匹配右侧,sub 将用空字符串替换它。

sub(".*_|^[^_]*$", "", col2)

【讨论】:

  • 谢谢@GGrothendieck,效果很好! [不过,我需要一段时间才能弄清楚这一切意味着什么。]
【解决方案2】:

使用stringi 包,您也可以实现您的目标。stri_extract_last_regex() 提取您在模式中指定的最后一个元素。在这里,我说“获取字符串中的最后一个小写字母”。同样,您可以使用stri_replace_last_regex() 修改col2。在这里我说“我想用空替换_的最后一个模式和一个小写字母。”也就是我说“我要去掉最后一个模式的_和一个小写字母。”

library(dplyr)
library(stringi)

df %>%
mutate(col3 = stri_extract_last_regex(str = col2, pattern = "[a-z]"),
       col2 = stri_replace_last_regex(str = col2, pattern = "_[a-z]", replacement = ""))

#  col1  col2 col3
#1    a     a    b
#2    b   a_b    c
#3    c a_b_c    d

【讨论】:

    【解决方案3】:

    strsplit 解决方案:

    spl <- strsplit(as.character(df$col2), "_")
    
    sapply(lapply(spl, head, -1), paste, collapse="_")
    #[1] "a"     "a_b"   "a_b_c"
    sapply(lapply(spl, tail, 1), paste, collapse="_")
    #[1] "b" "c" "d"
    

    或者去功能齐全的疯狂:

    Map(
      function(spl,ty,n) sapply(spl, function(x) paste(ty(x,n),collapse="_") ),
      list(strsplit(as.character(df$col2), "_")),
      c(head,tail),
      c(-1,1) 
    )
    #[[1]]
    #[1] "a"     "a_b"   "a_b_c"
    #
    #[[2]]
    #[1] "b" "c" "d"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-06
      相关资源
      最近更新 更多