【问题标题】:Replace multiple characters, by index, in a string quickly按索引快速替换字符串中的多个字符
【发布时间】:2019-11-28 19:32:25
【问题描述】:

我正在尝试将字符串中的多个字符快速替换为另一个字符,例如*

例如,我有一个字符串如:

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"

但很明显,应该有一些比我上面发布的更简单和更快的东西。有什么比我在这里演示的更简单、更快的方法吗?

【问题讨论】:

    标签: r string dplyr stringi


    【解决方案1】:

    base R中,除了@akrun,所示的substring()for-loop的方法外,还可以使用utf8ToInt()intToUtf8来制作

    v <- utf8ToInt(string)
    v[string_indexes_replaced ] <- utf8ToInt("*")
    res <- intToUtf8(v)
    

    给了

    > res
    [1] "*bc*e*gh*j"
    

    【讨论】:

    • @ThomasIsCoding 谢谢。如果到那时还没有更快的解决方案,我将在明天将其标记为已接受的答案。
    【解决方案2】:

    我们可以使用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"
    

    【讨论】:

    • 谢谢@akrun。在接受这个作为答案之前,我会稍等片刻,因为我想看看其他人是否有任何其他方法可以很好地扩展更长的字符串以及是否将其应用于字符串列表。
    • @InfiniteFlashChess 好的。我从stringi添加了一个选项
    • 太棒了。感谢您的努力和时间。您是社区的重要资源。
    • 您的stri_sub_all() 行很棒,但在我为我的任务做了一些基准测试之后,它比 Thomas 的要慢一些。
    【解决方案3】:

    一个简单的递归解决方案。时间效率应该与迭代(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"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-13
      • 2021-05-19
      相关资源
      最近更新 更多