我有这个载体myvec.我希望在第二个':'之后删除所有内容并获得结果.如何在第n个':'之后删除字符串?
myvec<- c("chr2:213403244:213403244:G:T:snp","chr7:55240586:55240586:T:G:snp" ,"chr7:55241607:55241607:C:G:snp")
result
chr2:213403244
chr7:55240586
chr7:55241607
Run Code Online (Sandbox Code Playgroud)
以下是一些替代方案.我们删除第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 = ":"))
Run Code Online (Sandbox Code Playgroud)
赠送:
[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
[3] "chr7:55241607:55241607"
Run Code Online (Sandbox Code Playgroud)
2)sprintf/sub构造适当的正则表达式(在下面的k等于3的情况下^((.*?:){2}.*?):.*)并使用它sub:
k <- 3
sub(sprintf("^((.*?:){%d}.*?):.*", k-1), "\\1", myvec)
Run Code Online (Sandbox Code Playgroud)
赠送:
[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
[3] "chr7:55241607:55241607"
Run Code Online (Sandbox Code Playgroud)
注1:对于k = 1,这可以进一步简化为sub(":.*", "", myvec),对于k = n-1,可以进一步简化为sub(":[^:]*$", "", myvec)
注2:这是一个k等于3 的常规正则表达式的可视化:
^((.*?:){2}.*?):.*
Run Code Online (Sandbox Code Playgroud)

3)迭代删除最后一个字段我们可以n-k使用上面注1中的最后一个正则表达式删除最后一个字段时间,如下所示:
n <- 6 # number of fields
k < - 3 # number of fields to retain
out <- myvec
for(i in seq_len(n-k)) out <- sub(":[^:]*$", "", out)
Run Code Online (Sandbox Code Playgroud)
如果我们想自动设置n,我们可以选择用以下方法替换上面的硬编码线路设置:
n <- count.fields(textConnection(myvec[1]), sep = ":")
Run Code Online (Sandbox Code Playgroud)
4)定位第k个冒号的位置使用定位冒号gregexpr的位置,然后从中提取第k个的位置,因为我们不想要尾随冒号.用于substr从相应的字符串中提取许多字符.
k <- 3
substr(myvec, 1, sapply(gregexpr(":", myvec), "[", k) - 1)
Run Code Online (Sandbox Code Playgroud)
赠送:
[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
[3] "chr7:55241607:55241607"
Run Code Online (Sandbox Code Playgroud)
注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]
Run Code Online (Sandbox Code Playgroud)
赠送:
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
Run Code Online (Sandbox Code Playgroud)
使用sprintf和sub的解决方案是最快的,尽管它使用复杂的正则表达式,而其他使用更简单或没有正则表达式,并且可能因简单而优选.
添加添加了其他解决方案和附加说明.
我们可以使用sub。我们匹配一个或多个不是:从字符串(^([^:]+)开头的:字符,然后是a ,再匹配一个不是a :([^:]+)的字符,将其放在捕获组中,即括号内。我们用替换中的捕获组(\\1)替换。
sub('^([^:]+:[^:]+).*', '\\1', myvec)
#[1] "chr2:213403244" "chr7:55240586" "chr7:55241607"
Run Code Online (Sandbox Code Playgroud)
上面的作品以示例为例。对于一般情况,要在第n个定界符之后删除,
n <- 2
pat <- paste0('^([^:]+(?::[^:]+){',n-1,'}).*')
sub(pat, '\\1', myvec)
#[1] "chr2:213403244" "chr7:55240586" "chr7:55241607"
Run Code Online (Sandbox Code Playgroud)
用不同的“ n”检查
n <- 3
Run Code Online (Sandbox Code Playgroud)
并重复相同的步骤
sub(pat, '\\1', myvec)
#[1] "chr2:213403244:213403244" "chr7:55240586:55240586"
#[3] "chr7:55241607:55241607"
Run Code Online (Sandbox Code Playgroud)
或另一个选择是将n个组件分开:,然后再将它们分开paste。
n <- 2
vapply(strsplit(myvec, ':'), function(x)
paste(x[seq.int(n)], collapse=':'), character(1L))
#[1] "chr2:213403244" "chr7:55240586" "chr7:55241607"
Run Code Online (Sandbox Code Playgroud)