stringr包具有有用的str_replace()
和str_replace_all()
功能。例如
mystring <- "one fish two fish red fish blue fish"
str_replace(mystring, "fish", "dog") # replaces the first occurrence
str_replace_all(mystring, "fish", "dog") # replaces all occurrences
真棒。但你怎么样?
答案 0 :(得分:2)
一个有用的答案很大程度上取决于字符串以及你对它的了解。使用正则表达式,一个选项是构建一个匹配整行的正则表达式,但是在不同的部分,所以你可以把你喜欢的部分放回去:
str_replace(mystring, '(^.*?fish.*?)(fish)(.*?fish.*)', '\\1dog\\3')
# [1] "one fish two dog red fish blue fish"
其中替换中的\\1
和\\3
分别与捕获的第一个和第三个括号匹配。请注意懒惰(不合理)量词*?
,这些非常重要,因此您不会过度匹配。
当然,你可以做同样的事情来匹配第三次或第四次:
str_replace(mystring, '(^.*?fish.*?fish.*?)(fish)(.*)', '\\1dog\\3')
# [1] "one fish two fish red dog blue fish"
str_replace(mystring, '(^.*?fish.*?fish.*?fish.*?)(fish)(.*?)', '\\1dog\\3')
# [1] "one fish two fish red fish blue dog"
但这并不是非常有效。您可以使用量词来重复,但它们使替换组的编号有点混乱:
str_replace(mystring, '^((.*?fish.*?){3})(fish)(.*?)', '\\1dog\\4')
# [1] "one fish two fish red fish blue dog"
但是如果你让重复的组不捕获(?: ... )
,那就更有意义了:
str_replace(mystring, '^((?:.*?fish.*?){3})(fish)(.*?)', '\\1dog\\3')
# [1] "one fish two fish red fish blue dog"
但所有这些都是很多正则表达式。一个更简单的选择(取决于上下文和你喜欢的正则表达式,我想)可能是使用strsplit
然后重新组合,collapse
分开:
mystrlist <- strsplit(mystring, 'fish ')[[1]] # match the space so not the last "fish$"
paste0(c(mystrlist[1],
paste0(mystrlist[2:3], collapse = 'dog '),
mystrlist[4]),
collapse = 'fish ')
# [1] "one fish two dog red fish blue fish"
paste0(c(mystrlist[1:2],
paste0(mystrlist[3:4], collapse = 'dog ')),
collapse = 'fish ')
# [1] "one fish two fish red dog blue fish"
当然,对于最后一个单词,这并不是非常好用,但行尾正则表达式$
使用str_replace
(或只是sub
)非常容易达到这个目的:
sub('fish$', 'dog', mystring)
# [1] "one fish two fish red fish blue dog"
底线:很大程度上取决于上下文最佳选择是什么,但遗憾的是没有额外的参数来替换哪个匹配。
答案 1 :(得分:2)
对于第一个和最后一个,我们可以使用stri_replace
中的stringi
,因为它有选项
library(stringi)
stri_replace(mystring, fixed="fish", "dog", mode="first")
#[1] "one dog two fish red fish blue fish"
stri_replace(mystring, fixed="fish", "dog", mode="last")
#[1] "one fish two fish red fish blue dog"
mode
只能包含'first','last'和'all'值。因此,其他选项不在默认功能中。我们可能必须使用regex
选项来更改它。
使用sub
,我们可以进行第n次替换
sub("^((?:(?!fish).)*fish(?:(?!fish).)*)fish",
"\\1dog", mystring, perl=TRUE)
#[1] "one fish two dog red fish blue fish"
或者我们可以使用
sub('^((.*?fish.*?){2})fish', "\\1\\dog", mystring, perl=TRUE)
#[1] "one fish two fish red dog blue fish"
为了方便起见,我们可以创建一个功能来执行此操作
patfn <- function(n){
stopifnot(n>1)
sprintf("^((.*?\\bfish\\b.*?){%d})\\bfish\\b", n-1)
}
并替换第n个'fish'除了第一个'fish',可以使用sub
或str_replace
sub(patfn(2), "\\1dog", mystring, perl=TRUE)
#[1] "one fish two dog red fish blue fish"
sub(patfn(3), "\\1dog", mystring, perl=TRUE)
#[1] "one fish two fish red dog blue fish"
sub(patfn(4), "\\1dog", mystring, perl=TRUE)
#[1] "one fish two fish red fish blue dog"
这也适用于str_replace
str_replace(mystring, patfn(2), "\\1dog")
#[1] "one fish two dog red fish blue fish"
str_replace(mystring, patfn(3), "\\1dog")
#[1] "one fish two fish red dog blue fish"
根据上面提到的模式/替换,我们可以创建一个新功能来完成大部分选项
replacerFn <- function(String, word, rword, n){
stopifnot(n >0)
pat <- sprintf(paste0("^((.*?\\b", word, "\\b.*?){%d})\\b",
word,"\\b"), n-1)
rpat <- paste0("\\1", rword)
if(n >1) {
stringr::str_replace(String, pat, rpat)
} else {
stringr::str_replace(String, word, rword)
}
}
replacerFn(mystring, "fish", "dog", 1)
#[1] "one dog two fish red fish blue fish"
replacerFn(mystring, "fish", "dog", 2)
#[1] "one fish two dog red fish blue fish"
replacerFn(mystring, "fish", "dog", 3)
#[1] "one fish two fish red dog blue fish"
replacerFn(mystring, "fish", "dog", 4)
#[1] "one fish two fish red fish blue dog"
答案 2 :(得分:0)
stringr
设计用于处理字符向量。它没有允许在矢量元素内进行任何详细级别播放的功能。但是一种简单的方法是将字符串拆分为子集的字符向量,在该向量上应用stringr
函数(因为stringr
确实很擅长),然后将向量重新合并为一个串。当然,这些步骤可以转换为功能。
只要需要在单个字符串中执行某些操作,就可以应用此方法。
对于此处提供的示例,合适的子集是单个单词。
因此,要替换字符串的第n个元素:
library(stringr)
replace_function <- function(string, word, rword, n) {
vec <- unlist(strsplit(string, " "))
vec[str_which(vec, word)[n]] <- rword
str_c(vec, collapse = " ")
}
replace_function(mystring, "fish", "dog", 1)
[1] "one dog two fish red fish blue fish"
replace_function(mystring, "fish", "dog", 2)
[1] "one fish two dog red fish blue fish"
要添加最后一个元素中的第n个元素,只需添加rev()
:
replace_end_function <- function(string, word, rword, n) {
vec <- unlist(strsplit(string, " "))
vec[rev(str_which(vec, word))[n]] <- rword
str_c(vec, collapse = " ")
}
replace_end_function(mystring, "fish", "dog", 1)
[1] "one fish two fish red fish blue dog"
replace_end_function(mystring, "fish", "dog", 2)
[1] "one fish two fish red dog blue fish"
并将第n个元素替换为最后一个元素:
replace_end_function <- function(string, word, rword, n) {
vec <- unlist(strsplit(string, " "))
vec[str_which(vec, word)[n:length(str_which(vec, word))]] <- rword
str_c(vec, collapse = " ")
}
replace_end_function(mystring, "fish", "dog", 1)
[1] "one dog two dog red dog blue dog"
replace_end_function(mystring, "fish", "dog", 2)
[1] "one fish two dog red dog blue dog"
replace_end_function(mystring, "fish", "dog", 3)
[1] "one fish two fish red dog blue dog"
replace_end_function(mystring, "fish", "dog", 4)
[1] "one fish two fish red fish blue dog"
请注意,此答案不使用OP所要求的str_replace()
,因为正如OP所指出的,str_replace()
仅适用于向量的第一个元素,而str_replace_all()
则适用在所有这些上。因此,它们不是stringr
包中最合适的函数来回答这个问题:用str_which()
的结果进行索引更合适(当然,一旦将单个字符串拆分为字符串向量, )。