从字符串中选择每第n个字符

9
我有一串由随机字母、空格和句点组成的字符串。我想从中获取每个第n个值(例如每10个)。我的想法是,如果我可以转置它,那么我就可以使用行号来选择每个第n个值。感谢您的任何帮助!
string <- "hutmnycdsldzlkt.ytairuaypk  dq.gubgp hyfjuwvpcdmvqxfcuhapnx"
5个回答

9

为了跟进 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"

7
我们可以拆分字符串,并使用 seq 来获取元素。
v1 <- strsplit(string, "")[[1]]
v1[seq(1, by = 10, length(v1))]
#[1] "h" "d" "r" "." "j" "x"

使用正则表达式的lookaround语法:
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"

5

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 函数,并通过将每个 x 值与最大的 i 序列多次 rep 以及仅调用一次 substring 函数来使其更快。类似这样:func2 <- function(x, n, start = 1) { mnc <- max(nchar(x)); i <- seq.int(start, mnc, by = n); paste(substring(rep(x, each=length(i)), i, i), collapse="") } - thelatemail
是的,我曾经考虑过这个问题。我的初始想法(在此处编码)有意尝试不超出字符串长度的 substring,但事后发现超出索引会默默地变成0长度,所以这是一个不必要的预防措施。我认为你的方法肯定更简单,也更快。谢谢,@thelatemail。 - r2evans
1
虽然我可能说得太早了 - 我的编辑结果仍然需要以某种方式分离向量元素,所以它还不完全正确。 - thelatemail

1

好的,这是对@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 

0
一种使用substring + seq + nchar的基本R选项。
substring(
  string,
  v <- seq(1, nchar(string), by = 10),
  v
)

提供

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接