首页 > 解决方案 > 获取r中字符串中模式的重叠位置

问题描述

客观的:

在允许重叠的字符串中查找模式的所有位置(开始和结束索引)。

方法:

这些stri_locate_all_*函数返回一个模式在字符串中的位置列表。该列表包括包含每个匹配位置的开始索引和结束索引的矩阵。这对我的目的很方便。

对于固定模式,以下方法效果很好:

s <- "---"
pattern <- "--"
stri_locate_all_fixed(s, pattern, overlap = TRUE)
[[1]]
    start   end
[1,]    1   2
[1,]    2   3

字符串“s”中出现了两次模式“--”。第一个从 s 的索引 1 开始,到索引 2 结束;第二个从索引 2 开始,到索引 3 结束。

---
---

但是,在我的情况下,模式可能包含多个允许的字符(以任何顺序或组合),并且模式的长度可能会改变。因此,“正则表达式”似乎比“固定”更合适。

考虑模式长度为 2,由“-”和“1”的任意组合(即“-1”、“1-”、“--”、“11”)和stri_locate_all_regex.

pattern <- "[1|-]{2}"
s <- "-1-"    
stri_locate_all_regex(s, pattern)
[[1]]
    start   end
[1,]    1   2

请注意,stri_locate_all_regex不使用重叠属性,因此如果我想捕获重叠,则必须调整模式。

根据各种消息来源,我需要在我的正则表达式中添加一个积极的前瞻性。

pattern <- "(?=[1|-]{2})"

此模式应该(并且在regex101 测试仪上进行测试时确实如此)找到模式的重叠出现。

但是,当使用stri_locate_all_regex返回的值不是我想要的。

stri_locate_all_regex("---", "(?=[1|-]{2})")
[[1]]
     start end
[1,]     1   0
[2,]     2   1

在这里,该函数正确识别出存在两个匹配项并记录了起始索引,但结束索引低于起始索引。

Stringi文档指出:

“对于 stri_locate_*_regex,如果匹配长度为 0,则 end 将比 start 少一个字符。”

这表明匹配长度为 0;正则表达式“lookarounds”的描述进一步支持了这一观察:

“Lookahead 和lookbehind,统称为‘lookaround’,是零长度断言……lookaround 实际上匹配字符,但随后放弃匹配,只返回结果:匹配或不匹配。”

所以,我的问题似乎在于使用积极的前瞻断言,该断言似乎在“开始”索引处返回零长度位置。

我的提炼问题:

- 是否有更好的正则表达式方法来捕获重叠(非零长度)匹配?或者,

- 是否有比stri_locate_all_regex实现所需输出更好的 r 函数(字符串中模式匹配的所有开始/结束位置的列表)

谢谢!

标签: rregex

解决方案


您可以将gregexprPCRE 正则表达式与包含整个正向前瞻模式的捕获组一起使用:

pattern <- "(?=([1-]{2}))"
s <- "-1-"
res <- gregexpr(pattern, s, perl=TRUE)
starts <- attr(res[[1]],'capture.start') 
lengths <- attr(res[[1]],'capture.length')
ends <- starts + lengths - 1
df_positions <- do.call(rbind, Map(data.frame, start=starts, end=ends, length=lengths))
df_positions

输出:

  start end length
1     1   2      2
2     2   3      2

查看R 演示


推荐阅读