如何用列表中的匹配字符串替换字符串?
How to replace strings with the matching string from a list?
假设我有一个列 df1$z
,其中包含一些“脏”字符串
> df1$z
[1] alpha uybkh kilo-mdjfyrs lima qxaucnpe gamma-qpnej
[5] beta-okmwy beta-uybkh gamma mdjfyrs lima qxaucnpe
[9] beta qpnej kilo okmwy
9 Levels: alpha uybkh beta-okmwy beta-uybkh ... lima qxaucnpe
一些字符串以包含在另一个向量中的模式开头 a
。
> a
[1] "alpha" "beta" "gamma"
这些a
匹配的字符串在z
我想用相应的向量模式替换a
所以结果如下:
# [1] "alpha" "kilo-mdjfyrs" "lima qxaucnpe" "gamma"
# [5] "beta" "beta" "gamma" "lima qxaucnpe"
# [9] "beta" "kilo okmwy"
我写了一个让我接近的函数,但它不是立即替换字符串,我无法把它们放在一起:
> lapply(seq_along(a), function(x) {z[grep(paste0("^", a[x]), z)] <- a[x]; z})
[[1]]
[1] "beta sfrmyijl" "lima-xudwfkm" "lima-kirvpys" "gamma wriygcb"
[5] "alpha" "alpha" "kilo xudwfkm" "alpha"
[9] "gamma wriygcb" "kilo-wvxgar"
[[2]]
[1] "beta" "lima-xudwfkm" "lima-kirvpys" "gamma wriygcb"
[5] "alpha wvxgar" "alpha-sfrmyijl" "kilo xudwfkm" "alpha-kirvpys"
[9] "gamma wriygcb" "kilo-wvxgar"
[[3]]
[1] "beta sfrmyijl" "lima-xudwfkm" "lima-kirvpys" "gamma"
[5] "alpha wvxgar" "alpha-sfrmyijl" "kilo xudwfkm" "alpha-kirvpys"
[9] "gamma" "kilo-wvxgar"
我也失败了一些 mapply()
方法,我认为这些方法在这里可能会有帮助,并研究了一些现有的答案,比如 this one,但我无法适应我的具体问题。
那么我该如何以高效的 base R 方式做到这一点呢? 注意替换应该放回数据框df1
而不打乱行的顺序。
数据
a <- c("alpha", "beta", "gamma")
set.seed(105056)
z <- paste0(sample(c(a, "kilo", "lima"), 10, replace=TRUE),
sample(c("-", " "), 10, replace=TRUE),
replicate(5, paste0(sample(letters, sample(5:9)), collapse="")))
df1 <- data.frame(z, x=rnorm(10))
我们可以使用 sub
。从 'a' 生成单个字符串后,使用 paste
创建一个模式,然后使用它在替换
中捕获具有反向引用 (\1
) 的模式
sub(paste0(".*\b(", paste(a, collapse="|"), ")\b.*"), "\1", df1$z)
#[1] "alpha" "kilo-mdjfyrs" "lima qxaucnpe" "gamma" "beta" "beta" "gamma"
#[8] "lima qxaucnpe" "beta" "kilo okmwy"
注意:sub
解决方案首先发布在这里
或使用 stringr
中的 str_replace
library(tidyverse)
df1 %>%
mutate(z = str_replace(z,
paste0(".*\b(", paste(a, collapse="|"), ")\b.*"), "\1"))
# z x
#1 alpha -0.18973111
#2 kilo-mdjfyrs -0.88150363
#3 lima qxaucnpe 0.01665189
#4 gamma 0.62647841
#5 beta -0.29526632
#6 beta 0.42480082
#7 gamma 1.03653486
#8 lima qxaucnpe -1.51910745
#9 beta 1.21504343
#10 kilo okmwy 1.25321421
您可以使用以下sub
解决方案:
> sub(paste0(".*\b(",paste(a, collapse="|"),")\b.*"), "\1", df1$z)
[1] "alpha" "kilo-mdjfyrs" "lima qxaucnpe" "gamma" "beta"
[6] "beta" "gamma" "lima qxaucnpe" "beta" "kilo okmwy"
该模式将匹配您的 a
向量中关键字前后的任何字符,并将关键字捕获到第 1 组,而
替换模式将仅保留找到的关键字并丢弃所有它前后的文本。如果没有匹配,则不会有任何变化。
参见regex demo。
这里有一个更长但更不透明的解决方案,使用 ifelse
和 grepl
:
df1$z <- ifelse(grepl("alpha.*", df1$z), a[1],
ifelse(grepl("beta.*", df1$z), a[2],
ifelse(grepl("gamma.*", df1$z), a[3], as.character(df1$z))))
df1
z x
1 alpha -0.18973111
2 kilo-mdjfyrs -0.88150363
3 lima qxaucnpe 0.01665189
4 gamma 0.62647841
5 beta -0.29526632
6 beta 0.42480082
7 gamma 1.03653486
8 lima qxaucnpe -1.51910745
9 beta 1.21504343
10 kilo okmwy 1.25321421
假设我有一个列 df1$z
,其中包含一些“脏”字符串
> df1$z
[1] alpha uybkh kilo-mdjfyrs lima qxaucnpe gamma-qpnej
[5] beta-okmwy beta-uybkh gamma mdjfyrs lima qxaucnpe
[9] beta qpnej kilo okmwy
9 Levels: alpha uybkh beta-okmwy beta-uybkh ... lima qxaucnpe
一些字符串以包含在另一个向量中的模式开头 a
。
> a
[1] "alpha" "beta" "gamma"
这些a
匹配的字符串在z
我想用相应的向量模式替换a
所以结果如下:
# [1] "alpha" "kilo-mdjfyrs" "lima qxaucnpe" "gamma"
# [5] "beta" "beta" "gamma" "lima qxaucnpe"
# [9] "beta" "kilo okmwy"
我写了一个让我接近的函数,但它不是立即替换字符串,我无法把它们放在一起:
> lapply(seq_along(a), function(x) {z[grep(paste0("^", a[x]), z)] <- a[x]; z})
[[1]]
[1] "beta sfrmyijl" "lima-xudwfkm" "lima-kirvpys" "gamma wriygcb"
[5] "alpha" "alpha" "kilo xudwfkm" "alpha"
[9] "gamma wriygcb" "kilo-wvxgar"
[[2]]
[1] "beta" "lima-xudwfkm" "lima-kirvpys" "gamma wriygcb"
[5] "alpha wvxgar" "alpha-sfrmyijl" "kilo xudwfkm" "alpha-kirvpys"
[9] "gamma wriygcb" "kilo-wvxgar"
[[3]]
[1] "beta sfrmyijl" "lima-xudwfkm" "lima-kirvpys" "gamma"
[5] "alpha wvxgar" "alpha-sfrmyijl" "kilo xudwfkm" "alpha-kirvpys"
[9] "gamma" "kilo-wvxgar"
我也失败了一些 mapply()
方法,我认为这些方法在这里可能会有帮助,并研究了一些现有的答案,比如 this one,但我无法适应我的具体问题。
那么我该如何以高效的 base R 方式做到这一点呢? 注意替换应该放回数据框df1
而不打乱行的顺序。
数据
a <- c("alpha", "beta", "gamma")
set.seed(105056)
z <- paste0(sample(c(a, "kilo", "lima"), 10, replace=TRUE),
sample(c("-", " "), 10, replace=TRUE),
replicate(5, paste0(sample(letters, sample(5:9)), collapse="")))
df1 <- data.frame(z, x=rnorm(10))
我们可以使用 sub
。从 'a' 生成单个字符串后,使用 paste
创建一个模式,然后使用它在替换
\1
) 的模式
sub(paste0(".*\b(", paste(a, collapse="|"), ")\b.*"), "\1", df1$z)
#[1] "alpha" "kilo-mdjfyrs" "lima qxaucnpe" "gamma" "beta" "beta" "gamma"
#[8] "lima qxaucnpe" "beta" "kilo okmwy"
注意:sub
解决方案首先发布在这里
或使用 stringr
str_replace
library(tidyverse)
df1 %>%
mutate(z = str_replace(z,
paste0(".*\b(", paste(a, collapse="|"), ")\b.*"), "\1"))
# z x
#1 alpha -0.18973111
#2 kilo-mdjfyrs -0.88150363
#3 lima qxaucnpe 0.01665189
#4 gamma 0.62647841
#5 beta -0.29526632
#6 beta 0.42480082
#7 gamma 1.03653486
#8 lima qxaucnpe -1.51910745
#9 beta 1.21504343
#10 kilo okmwy 1.25321421
您可以使用以下sub
解决方案:
> sub(paste0(".*\b(",paste(a, collapse="|"),")\b.*"), "\1", df1$z)
[1] "alpha" "kilo-mdjfyrs" "lima qxaucnpe" "gamma" "beta"
[6] "beta" "gamma" "lima qxaucnpe" "beta" "kilo okmwy"
该模式将匹配您的 a
向量中关键字前后的任何字符,并将关键字捕获到第 1 组,而 替换模式将仅保留找到的关键字并丢弃所有它前后的文本。如果没有匹配,则不会有任何变化。
参见regex demo。
这里有一个更长但更不透明的解决方案,使用 ifelse
和 grepl
:
df1$z <- ifelse(grepl("alpha.*", df1$z), a[1],
ifelse(grepl("beta.*", df1$z), a[2],
ifelse(grepl("gamma.*", df1$z), a[3], as.character(df1$z))))
df1
z x
1 alpha -0.18973111
2 kilo-mdjfyrs -0.88150363
3 lima qxaucnpe 0.01665189
4 gamma 0.62647841
5 beta -0.29526632
6 beta 0.42480082
7 gamma 1.03653486
8 lima qxaucnpe -1.51910745
9 beta 1.21504343
10 kilo okmwy 1.25321421