将序列拆分为子序列(可能使用正则表达式)

split sequence into subsequences (possibly with a regex)

我有一个序列,它是一个字符序列,主要是零,一小块看起来像这样:

0001001099991091010000100005480010000

我想得到所有由一个或多个零分隔的部分。所以在上述情况下,返回的正确值将是:

1,1,99991,91,1,1,548,1 (the commas are for illustration only)

我认为向量列表作为返回的数据结构最有意义,但我可以使用我认为合理的任何东西。我有数万个字符串,每个字符串最多有一千个字符。不过,唯一的字符是 0 到 9。这看起来可能是一个正则表达式问题,但我的正则表达式技能还不够好,甚至无法确定它是一个好的正则表达式问题。如果正则表达式是答案,有人可以帮我解决这个问题吗?

如果字符串与显示的一样,那么 strplit() 可以为您完成此操作:

vec <- "0001001099991091010000100005480010000"
strsplit(vec, "[0]+")

给予

> strsplit(vec, "[0]+")
[[1]]
[1] ""      "1"     "1"     "99991" "91"    "1"     "1"     "548"   "1"

这是一个包含一个组件的列表(我们将一个字符串传递给它进行拆分)但是如果您将 n 个字符串传递给一个向量,则返回的对象将具有 n 个组件。每个组件都包含您想要的子字符串。

如果您希望将这些作为数字,则需要转换为数字,但这很简单。另一个问题是示例字符串开头的 000 的 运行。这导致空字符串 "" 是拆分字符串的第一个元素。我们也需要删除它们。

out <- strsplit(vec, "[0]+")
out <- lapply(out, function(x) as.numeric(x[nzchar(x)]))

这给出了

> out
[[1]]
[1]     1     1 99991    91     1     1   548     1

请注意所使用的正则表达式:[0]+。括号括起我们要匹配的东西,在本例中只有 0s。 + 表示 "one or more of"。这就是为什么 strplit() 会在有一个或多个 0 的地方切碎提供的字符串的原因。

@gavin 的回答比较优雅,但是暴力法也可以:

input = '0001001099991091010000100005480010000'
output = character(0)
while(nchar(input)){
    if(grepl('^0',input)){
        # get rid of the unwanted bits
        input = gsub('^0+','',input)
        next
    }
    # keep the good bits
    output = c(output,gsub('0.*','',input))
    input = gsub('^[1-9]*','',input)
}

对于数千个字符串,您可能需要使用非常高效的 stringi 包。

x <- "0001001099991091010000100005480010000"

library(stringi)
stri_sub(x, stri_locate_all_regex(x, "[^0]+")[[1L]])
# [1] "1"     "1"     "99991" "91"    "1"     "1"     "548"   "1" 

基本上这是在 x 中定位所有非零字符块并返回子字符串。要将此方法应用于多个字符串,您可以使用 Map()

y <- rep(x, 3)
Map(stri_sub, y, stri_locate_all_regex(y, "[^0]+"))
# $`0001001099991091010000100005480010000`
# [1] "1"     "1"     "99991" "91"    "1"     "1"     "548"   "1"    
#
# $`0001001099991091010000100005480010000`
# [1] "1"     "1"     "99991" "91"    "1"     "1"     "548"   "1"    
#
# $`0001001099991091010000100005480010000`
# [1] "1"     "1"     "99991" "91"    "1"     "1"     "548"   "1"    

包中还有一个stri_split()函数,但是它会保留开头的空字符(如strsplit())和结尾的空字符为零。