如何删除R中第n个分隔符后的所有内容?

时间:2015-10-11 05:52:30

标签: r regex

我有这个向量str。我希望在第二个'之后删除所有内容:'并得到结果。如何在第n次'之后删除字符串:'?

myvec

2 个答案:

答案 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}.*?):.*

Regular expression visualization

Debuggex Demo

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