拆分字符串最后一个分隔符
split string last delimiter
当我在 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')
这些不使用包。他们假设 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)
一个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"
使用 stringi
包,您也可以实现您的目标。stri_extract_last_regex()
提取您在模式中指定的最后一个元素。在这里,我说的是"get the last small letter in a string.",同样,你可以用stri_replace_last_regex()
修饰col2
。这里我说的是"I want to replace the last pattern of _ and a small letter with nothing."也就是我说的是"I want to remove the last pattern of _ and a small letter."
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
当我在 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')
这些不使用包。他们假设 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)
一个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"
使用 stringi
包,您也可以实现您的目标。stri_extract_last_regex()
提取您在模式中指定的最后一个元素。在这里,我说的是"get the last small letter in a string.",同样,你可以用stri_replace_last_regex()
修饰col2
。这里我说的是"I want to replace the last pattern of _ and a small letter with nothing."也就是我说的是"I want to remove the last pattern of _ and a small letter."
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