我有这个向量str
。我希望在第二个'之后删除所有内容:'并得到结果。如何在第n次'之后删除字符串:'?
myvec
答案 0 :(得分:6)
以下是一些替代方案。我们删除第k个冒号及其后的所有内容。问题中的例子对应于k = 2.在下面的例子中,我们使用k = 3。
1)read.table 将数据读入data.frame,挑选出所需的列并将其重新粘贴在一起:
k <- 3 # keep first 3 fields only
do.call(paste, c(read.table(text = myvec, sep = ":")[1:k], sep = ":"))
,并提供:
[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
[3] "chr7:55241607:55241607"
2)sprintf / sub 构造适当的正则表达式(在k等于3的情况下,它将是^((.*?:){2}.*?):.*
)并将其与sub
一起使用:< / p>
k <- 3
sub(sprintf("^((.*?:){%d}.*?):.*", k-1), "\\1", myvec)
,并提供:
[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
[3] "chr7:55241607:55241607"
注1:对于k = 1,这可以进一步简化为sub(":.*", "", myvec)
,对于k = n-1,可以进一步简化为sub(":[^:]*$", "", myvec)
注2:以下是k
的常规正则表达式的可视化,等于3:
^((.*?:){2}.*?):.*
3)迭代删除最后一个字段我们可以使用上面注1中的最后一个正则表达式删除最后一个字段n-k
次,如下所示:
n <- 6 # number of fields
k < - 3 # number of fields to retain
out <- myvec
for(i in seq_len(n-k)) out <- sub(":[^:]*$", "", out)
如果我们想自动设置n,我们可以选择用以下代码替换上面的硬编码行设置:
n <- count.fields(textConnection(myvec[1]), sep = ":")
4)定位第k个冒号的位置使用gregexpr
找到冒号的位置,然后从中提取第k个的位置,因为我们不想使用尾随冒号。使用substr
从相应的字符串中提取多个字符。
k <- 3
substr(myvec, 1, sapply(gregexpr(":", myvec), "[", k) - 1)
,并提供:
[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
[3] "chr7:55241607:55241607"
注3:假设有n个字段。问题要求删除第k个分隔符后的所有内容,以便解决方案适用于k = 1,2,...,n-1。它不需要用于k = n,因为没有n个分隔符;但是,如果我们将k定义为要返回的字段数,那么k = n是有意义的,事实上,(1)和(3)也适用于那种情况。 (2)和(4)不适用于此扩展程序,但我们可以使用paste0(myvec, ":")
作为输入而不是myvec
轻松地将其用于工作。
注4:我们比较效果:
library(rbenchmark)
benchmark(
.read.table = do.call(paste, c(read.table(text = myvec, sep = ":")[1:k], sep = ":")),
.sprintf.sub = sub(sprintf("^((.*?:){%d}.*?):.*", k-1), "\\1", myvec),
.for = { out <- myvec; for(i in seq_len(n-k)) out <- sub(":[^:]*$", "", out)},
.gregexpr = substr(myvec, 1, sapply(gregexpr(":", myvec), "[", k) - 1),
order = "elapsed", replications = 1000)[1:4]
,并提供:
test replications elapsed relative
2 .sprintf.sub 1000 0.11 1.000
4 .gregexpr 1000 0.14 1.273
3 .for 1000 0.15 1.364
1 .read.table 1000 2.16 19.636
使用sprintf和sub的解决方案是最快的,尽管它使用复杂的正则表达式,而其他使用更简单或没有正则表达式,并且可能因简单而优先使用。
已添加添加了其他解决方案和其他说明。
答案 1 :(得分:4)
我们可以使用sub
。我们匹配字符串开头(:
)后面不是^([^:]+
的一个或多个字符,后跟:
,后跟另外一个不是:
的字符({ {1}}),将其放在捕获组中,即括号内。我们将替换为替换中的捕获组([^:]+
)。
\\1
以上作品发布的示例。对于在第n个分隔符后删除的一般情况,
sub('^([^:]+:[^:]+).*', '\\1', myvec)
#[1] "chr2:213403244" "chr7:55240586" "chr7:55241607"
使用不同的'n'检查
n <- 2
pat <- paste0('^([^:]+(?::[^:]+){',n-1,'}).*')
sub(pat, '\\1', myvec)
#[1] "chr2:213403244" "chr7:55240586" "chr7:55241607"
并重复相同的步骤
n <- 3
或者另一种选择是将sub(pat, '\\1', myvec)
#[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
#[3] "chr7:55241607:55241607"
和:
分成n个组件。
paste