按索引快速替换字符串中的多个字符
Replace multiple characters, by index, in a string quickly
我正在尝试用另一个字符快速替换字符串中的多个字符,例如 *
比如我有这样一个字符串:
string = "abcdefghij"
我还有一个索引向量,指示我想用另一个字符替换上面字符串中的字母的位置。
string_indexes_replaced = c(1, 4, 6, 9)
期望输出:
"*bc*e*gh*j"
我做了什么
我尝试了一种非常新手的方法,将字符拆分成一个列表,用 *
替换字符,然后将列表折叠回所需的字符串,如下所示:
library(dplyr)
library(stringi)
string%>%
strsplit(split = "")%>%
lapply(function(x) replace(x, string_indexes_replaced, rep("*", length(string_indexes_replaced))))%>%
lapply(stri_flatten)%>%
unlist(use.names = FALSE)
输出
"*bc*e*gh*j"
但很明显,应该有比我上面发布的更简单、更快的东西。有什么比我在这里演示的更简单、更快捷的吗?
我们可以使用substring
v1 <- c(1, 4, 6, 9)
for(i in seq_along(v1)) substring(string, v1[i], v1[i]) <- "*"
#[1] "*bc*e*gh*j"
由于我们使用的是stringi
,另一个选项是
library(stringi)
stri_sub_all(string, from = v1, length = 1) <- "*"
string
#[1] "*bc*e*gh*j"
在base R
中,除了中substring()
和for-loop
的方法外,还可以用utf8ToInt()
和intToUtf8
来成功
v <- utf8ToInt(string)
v[string_indexes_replaced ] <- utf8ToInt("*")
res <- intToUtf8(v)
这给出了
> res
[1] "*bc*e*gh*j"
一个简单的递归解决方案。时间效率应与迭代(for 循环)相同。好处是没有副作用(整数 ks
的赋值是本地化的),因此我们可以将其整个计算视为功能抽象,并将其提供给我们正在处理的更大程序的其他部分。这将有助于模块化代码。
# multi-replace for character vector input with length greater than 1
multi_replace_v <- function(v, r, ks) {
ks <- as.integer(ks)
if (length(ks) == 0) {
v
} else if (length(ks) == 1) {
if (ks[[1]] > length(v) | ks[[1]] < 1) {
stop("Invalid parameter: ks=", as.character(ks[[1]]), ". Valid range: 1-", as.character(length(v)))
} else if (ks[[1]] == 1) {
c(r, v[-1])
} else if (ks[[1]] == length(v)) {
c(v[-length(v)], r)
} else {
c(v[1:(ks[[1]]-1)], r, v[(ks[[1]]+1):length(v)])
}
} else {
multi_replace_v(multi_replace_v(v, r, ks[[1]]), r, ks[-1])
}
}
# multi-replace for input of single string character vector
multi_replace_s <- function(s, r, ks) paste0(multi_replace_v(unlist(strsplit(s, '')), r, ks), collapse = '')
# multi-replace for both single string and long vector input
multi_replace <- function(v_or_s, r, ks) {
if (length(v_or_s) == 1) {
multi_replace_s(v_or_s, r, ks)
} else if (length(v_or_s) > 1) {
multi_replace_v(v_or_s, r, ks)
} else {
NULL
}
}
# Example
> multi_replace('abcdefghij', "*", c(1,4,6,9))
[1] "*bc*e*gh*j"
我正在尝试用另一个字符快速替换字符串中的多个字符,例如 *
比如我有这样一个字符串:
string = "abcdefghij"
我还有一个索引向量,指示我想用另一个字符替换上面字符串中的字母的位置。
string_indexes_replaced = c(1, 4, 6, 9)
期望输出:
"*bc*e*gh*j"
我做了什么
我尝试了一种非常新手的方法,将字符拆分成一个列表,用 *
替换字符,然后将列表折叠回所需的字符串,如下所示:
library(dplyr)
library(stringi)
string%>%
strsplit(split = "")%>%
lapply(function(x) replace(x, string_indexes_replaced, rep("*", length(string_indexes_replaced))))%>%
lapply(stri_flatten)%>%
unlist(use.names = FALSE)
输出
"*bc*e*gh*j"
但很明显,应该有比我上面发布的更简单、更快的东西。有什么比我在这里演示的更简单、更快捷的吗?
我们可以使用substring
v1 <- c(1, 4, 6, 9)
for(i in seq_along(v1)) substring(string, v1[i], v1[i]) <- "*"
#[1] "*bc*e*gh*j"
由于我们使用的是stringi
,另一个选项是
library(stringi)
stri_sub_all(string, from = v1, length = 1) <- "*"
string
#[1] "*bc*e*gh*j"
在base R
中,除了substring()
和for-loop
的方法外,还可以用utf8ToInt()
和intToUtf8
来成功
v <- utf8ToInt(string)
v[string_indexes_replaced ] <- utf8ToInt("*")
res <- intToUtf8(v)
这给出了
> res
[1] "*bc*e*gh*j"
一个简单的递归解决方案。时间效率应与迭代(for 循环)相同。好处是没有副作用(整数 ks
的赋值是本地化的),因此我们可以将其整个计算视为功能抽象,并将其提供给我们正在处理的更大程序的其他部分。这将有助于模块化代码。
# multi-replace for character vector input with length greater than 1
multi_replace_v <- function(v, r, ks) {
ks <- as.integer(ks)
if (length(ks) == 0) {
v
} else if (length(ks) == 1) {
if (ks[[1]] > length(v) | ks[[1]] < 1) {
stop("Invalid parameter: ks=", as.character(ks[[1]]), ". Valid range: 1-", as.character(length(v)))
} else if (ks[[1]] == 1) {
c(r, v[-1])
} else if (ks[[1]] == length(v)) {
c(v[-length(v)], r)
} else {
c(v[1:(ks[[1]]-1)], r, v[(ks[[1]]+1):length(v)])
}
} else {
multi_replace_v(multi_replace_v(v, r, ks[[1]]), r, ks[-1])
}
}
# multi-replace for input of single string character vector
multi_replace_s <- function(s, r, ks) paste0(multi_replace_v(unlist(strsplit(s, '')), r, ks), collapse = '')
# multi-replace for both single string and long vector input
multi_replace <- function(v_or_s, r, ks) {
if (length(v_or_s) == 1) {
multi_replace_s(v_or_s, r, ks)
} else if (length(v_or_s) > 1) {
multi_replace_v(v_or_s, r, ks)
} else {
NULL
}
}
# Example
> multi_replace('abcdefghij', "*", c(1,4,6,9))
[1] "*bc*e*gh*j"