除了 3a 之外,这些假设您正在寻找 string 的第一个长度为 3 的子序列,其形式为 <TEXT> something <TEXT>;但是,如果在连续的<TEXT> 分量之间允许有任意数量的string 向量分量,则使用 3a 或 4a。
1) 如果 string 至少有 3 个元素,则创建一个三列移动窗口矩阵 m 并计算一个逻辑向量 ok,对于其中第 1 列和第3 等于<TEXT>。取m 的第二列的第一个元素,其中有一行ok 为TRUE。
如果没有匹配项,则此代码返回零长度字符向量。没有使用任何包。
m <- embed(string, 3)
ok <- !rowSums(m[, -2, drop = FALSE] != "<TEXT>")
head(m[ok, 2], 1)
## [1] "some text"
2) 对于e 的每一行,如果第一个和最后一个元素是<TEXT>,则返回中间元素,否则返回NA。
然后移除 NA 并取出剩下的第一个元素。
e <- embed(string, 3)
Select <- function(x) ifelse(all(x[-2] == "<TEXT>"), x[2], NA)
head(na.omit(apply(e, 1, Select)), 1)
## [1] "some text"
3) 另一种基本方法是创建一个与string 长度相同的分组向量g,每次遇到<TEXT> 时都会增加1。然后使用tapply 提取每个组的第二个元素,长度为 2 或 NA 如果其他长度。删除 NA 元素并取第一个剩下的元素。如果没有匹配的子序列,则返回零长度字符向量。
g <- cumsum(string == "<TEXT>")
Select2 <- function(x) if (length(x) == 2) x[2] else NA
ta <- tapply(string[g > 0], g[g > 0], Select2)
as.character(head(na.omit(c(ta)), 1))
## [1] "some text"
3a) 如果string 的多个组件在<TEXT> 组件之间是允许的,则进行以下修改。如果没有匹配的子序列,则返回 NULL。
g <- cumsum(string == "<TEXT>")
ta <- tapply(string[g > 0], g[g > 0], function(x) x[-1], simplify = FALSE)
unname(unlist((head(ta, 1))))
## [1] "some text"
4) 这会在每个 <TEXT> 元素之后查找元素并挑选出其中的第一个。如果只有一个 <TEXT> 则返回其后的元素,如果根本没有 <TEXT> 元素或唯一的 <TEXT> 元素出现在输入向量的末尾,则返回长度为 0 的字符向量。
head(string[c(FALSE, head(string, -1) == "<TEXT>")], 1)
## [1] "some text"
4a) 如果在<TEXT> 元素之间可以出现多个元素,请改用它。请注意,如果存在少于两个 <TEXT> 元素,则返回 NULL。如果我想在这种情况下返回其他内容,请在 if 中添加 else 分支。
ix <- head(which(string == "<TEXT>"), 2)
if (length(ix) == 2) string[seq(ix[1] + 1, ix[2] - 1)]
## [1] "some text"