我有以下代码来查找字符串中的模式(连续重复的子字符串),比如0110110110000
。输出模式为011
和110
,因为它们都在字符串中重复。可以对以下代码进行哪些更改?
我想识别从给定字符串中的任何位置开始的子串,并且至少重复阈值次数。在上面提到的字符串中,阈值是三(th = 3
)。重复的字符串应该是最大重复字符串。在上面的字符串中,110
和011
都满足这些条件。
我尝试这样做:
reps <- function(s, n) paste(rep(s, n), collapse = "") # repeat s n times
find.string <- function(string, th = 3, len = floor(nchar(string)/th)) {
for(k in len:1) {
pat <- paste0("(.{", k, "})", reps("\\1", th-1))
r <- regexpr(pat, string, perl = TRUE)
if (attr(r, "capture.length") > 0) break
}
if (r > 0) substring(string, r, r + attr(r, "capture.length")-1) else ""
}
答案 0 :(得分:3)
您可以使用regex
:
s <- '0110110110000'
thr <- 3
m <- gregexpr(sprintf('(?=(.+)(?:\\1){%s,})', thr-1), s, perl=TRUE)
unique(mapply(function(x, y) substr(s, x, x+y-1),
attr(m[[1]], 'capture.start'),
attr(m[[1]], 'capture.length')))
# [1] "011" "110" "0"
gregexpr
中的模式使用正向前瞻来防止匹配消耗字符(因此允许重叠匹配,例如011
和110
)。我们对捕获的组使用重复(至少thr - 1
次)反向引用来查找重复的子字符串。
然后我们可以通过从gregexpr
的结果的属性(即对象m
)中获取起始位置和长度来提取匹配的子串。
您没有指定最小字符串长度,因此返回0
作为重复的子字符串之一。如果考虑到最小和/或最大子字符串长度,则可以修改正则表达式的第一个子表达式。例如,以下内容仅匹配至少包含2个字符的子字符串。
sprintf('(?=(.{2,})(?:\\1){%s,})', thr-1)