分割字符串最后一个分隔符

6
我需要帮助解决如何在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')

1
顺便提一下,除非你想让自己的生活变得困难,否则不要使用 data.frame(cbind(...。它首先创建一个矩阵,然后再创建一个数据框并将所有内容更改为一种类型(例如,将数字更改为字符)。只需使用 data.frame(... 即可。 - thelatemail
谢谢@thelatemail。显然我正在学习,所以每一条建议都很有帮助。 - user42485
2
可能存在重复问题 - https://dev59.com/kmAf5IYBdhLWcg3wLAKq 和 https://dev59.com/PlwZ5IYBdhLWcg3wJ9nN - thelatemail
这个问题没有一个很好的答案。 - G. Grothendieck
3个回答

5
使用 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

2

这些代码不需要任何软件包。 假设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(".*_|^[^_]*$", "", col2)

谢谢@GGrothendieck,这完美地解决了问题![虽然,我需要一段时间来弄清楚它的含义。] - user42485

2
一个 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"

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