从字符串中选择每第 n 个字符
Posted
技术标签:
【中文标题】从字符串中选择每第 n 个字符【英文标题】:Select every nth character from a string 【发布时间】:2021-05-26 04:25:20 【问题描述】:我有一串带有随机空格和一些句点的随机字母。我想从中获取每第 n 个值(例如每 10 个)。我的想法是,如果我可以转置它,那么我可以使用行号来选择每个第 n 个值。任何帮助表示赞赏!
string <- "hutmnycdsldzlkt.ytairuaypk dq.gubgp hyfjuwvpcdmvqxfcuhapnx"
【问题讨论】:
【参考方案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 <- 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="")
是的,我已经考虑过了。我最初的想法(在此处编码)故意尝试不将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
【讨论】:
以上是关于从字符串中选择每第 n 个字符的主要内容,如果未能解决你的问题,请参考以下文章
选择每第 n 行作为 Pandas DataFrame 而无需读取整个文件
如何在 SQL (postgresql) 中选择每第 n 分钟的行