【问题标题】:Select every nth character from a string从字符串中选择每第 n 个字符
【发布时间】:2021-05-26 04:25:20
【问题描述】:

我有一串带有随机空格和一些句点的随机字母。我想从中获取每第 n 个值(例如每 10 个)。我的想法是,如果我可以转置它,那么我可以使用行号来选择每个第 n 个值。任何帮助表示赞赏!

string <- "hutmnycdsldzlkt.ytairuaypk  dq.gubgp hyfjuwvpcdmvqxfcuhapnx"

【问题讨论】:

    标签: r regex string substring stringr


    【解决方案1】:

    跟进 OP 的想法(“使用行号”)。拆分字符串,用 10 行填充一个矩阵,选择第一行。

    matrix(strsplit(x, "")[[1]], nrow = 10)[1, ]
    # [1] "h" "d" "r" "." "j" "x"
    

    您会收到回收警告,但这不会影响我们,因为我们选择了第一行。


    好啊charToRaw:

    rawToChar(charToRaw(x)[c(TRUE, rep(FALSE, 9))])
    # [1] "hdr.jx"
    

    【讨论】:

      【解决方案2】:

      我们可以拆分字符串,使用seq获取元素

      v1 <- strsplit(string, "")[[1]]
      v1[seq(1, by = 10, length(v1))]
      #[1] "h" "d" "r" "." "j" "x"
      

      或使用正则表达式环视

      library(stringr)
      str_replace_all(string, "(.).{1,9}", "\\1")
      #[1] "hdr.jx"
      

      或者使用glue使其动态化

      n <- 9
      str_replace_all(string, glue::glue("(.).{1,[n]}",
                .open = '[', .close = ']'), "\\1")
      #[1] "hdr.jx"
      

      【讨论】:

        【解决方案3】:

        substring 将采用first=last= 的向量,因此我们可以形成适当的序列并从那里开始。

        func <- function(x, n, start = 1) {
          vapply(x, function(z) {
            i <- seq.int(start, nchar(z), by = n)
            i <- i[i > 0]
            paste(substring(x, i, i), collapse = "")
          }, character(1))
        }
        
        func(string, 10)
        # hutmnycdsldzlkt.ytairuaypk  dq.gubgp hyfjuwvpcdmvqxfcuhapnx 
        #                                                    "hdr.jx" 
        

        每 10 个(从 1 开始)在哪里

        hutmnycdsldzlkt.ytairuaypk  dq.gubgp hyfjuwvpcdmvqxfcuhapnx 
        12345678901234567890123456789012345678901234567890123456789
        ^         ^         ^         ^         ^         ^
        h         d         r         .         j         x
        

        (我使用apply 变体的最大原因是,如果你有一个字符串向量,substring 可以优雅地工作。)

        【讨论】:

        • 我认为你可以避免vapply 并通过rep多次食用每个x 值以及最大i 序列然后只调用一次substring 来加快速度.比如:func2 &lt;- function(x, n, start = 1) { mnc &lt;- max(nchar(x)); i &lt;- seq.int(start, mnc, by = n); paste(substring(rep(x, each=length(i)), i, i), collapse="") }
        • 是的,我已经考虑过了。我最初的想法(在此处编码)故意尝试不将substring 超出字符串的长度,但事后看来,超出的索引长度为0,因此是不必要的预防措施。我认为您的方法肯定更简单,并且可能更快。谢谢,@thelatemail。
        • 虽然我可能说得太早了 - 我的编辑结果仍然必须以某种方式分解以分离矢量元素,所以它不太正确。
        【解决方案4】:

        使用substring + seq + nchar 的基本 R 选项

        substring(
          string,
          v <- seq(1, nchar(string), by = 10),
          v
        )
        

        给予

        "h" "d" "r" "." "j" "x"
        

        【讨论】:

          【解决方案5】:

          好的,这是对 @r2evans 答案的补充,它试图通过不必在每个单独的值上循环来加速矢量化 substring 操作。

          func2 <- function(x, n, start = 1) {
              mnc <- max(nchar(x))
              i <- seq.int(start, mnc, by = n)
              res <- paste(substring(rep(x, each=length(i)), i, i), collapse="")
              fi <- findInterval(nchar(x), i)
              substring(res, c(1, head(cumsum(fi),-1) + 1), cumsum(fi) )
          }   
          

          快速测试 20K 条记录:

          x <- c("12345678901234567890", "09876543210987654321")
          bigx <- rep(x,1e4)
          
          system.time(func(bigx, 10, 1))
          ##   user  system elapsed 
          ##  38.29    0.03   38.36 
          
          system.time(func2(bigx, 10, 1))
          ## user  system elapsed 
          ## 0.02    0.00    0.02 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-17
            • 1970-01-01
            • 2017-09-24
            • 1970-01-01
            • 2017-12-01
            相关资源
            最近更新 更多