【问题标题】:Overlapping matches in RR中的重叠匹配
【发布时间】:2014-09-12 02:56:48
【问题描述】:

我已经搜索到可以找到这个forum discussion来实现重叠匹配的效果。

我还发现了以下SO 问题,谈到查找索引以执行此任务,但无法找到任何关于在 R 语言中抓取重叠匹配项的简明内容。

我可以在支持 (PCRE) 的大多数语言中执行此任务,方法是使用肯定的前瞻断言,同时在前瞻内实现捕获组以捕获重叠匹配。

但是,虽然实际上以与我在其他语言中相同的方式执行此操作,在 R 中使用 perl=T,但没有结果。

> x <- 'ACCACCACCAC'
> regmatches(x, gregexpr('(?=([AC]C))', x, perl=T))[[1]]
[1] "" "" "" "" "" "" ""

同时使用 stringistringr 包也是如此。

> library(stringi)
> library(stringr)
> stri_extract_all_regex(x, '(?=([AC]C))')[[1]]
[1] "" "" "" "" "" "" ""
> str_extract_all(x, perl('(?=([AC]C))'))[[1]]
[1] "" "" "" "" "" "" ""

执行此操作时应返回的正确结果是:

[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"

编辑

  1. 我很清楚regmatches 不能很好地处理捕获的匹配,但是究竟 是什么导致了正则匹配中的这种行为,为什么没有返回结果? 我正在寻找一个比较详细的答案

  2. stringistringr 包是否无法在 regmatches 上执行此操作?

  3. 请随时添加到我的答案中或提出与我发现不同的解决方法。

【问题讨论】:

    标签: regex r string dna-sequence stringi


    【解决方案1】:

    标准regmatches 不适用于捕获的匹配项(特别是同一字符串中的多个捕获匹配项)。在这种情况下,由于您正在“匹配”前瞻(忽略捕获),因此匹配本身的长度为零。还有一个regmatches()&lt;- 函数可以说明这一点。观察

    x <- 'ACCACCACCAC'
    m <- gregexpr('(?=([AC]C))', x, perl=T)
    regmatches(x, m) <- "~"
    x
    # [1] "~A~CC~A~CC~A~CC~AC"
    

    注意所有字母是如何保存的,我们刚刚用我们可以观察到的东西替换了零长度匹配的位置。

    我创建了一个regcapturedmatches() 函数,我经常将其用于此类任务。例如

    x <- 'ACCACCACCAC'
    regcapturedmatches(x, gregexpr('(?=([AC]C))', x, perl=T))[[1]]
    
    #      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
    # [1,] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
    

    gregexpr 可以很好地抓取所有数据,因此如果您不想使用此辅助函数,您可以从该对象中提取数据。

    【讨论】:

    • +1 您创建的有趣函数。我很清楚零宽度匹配,所以基本上 regmatches 和 stringi、r 等其他包不打算处理这个?
    • 我无法与stringr 交谈,因为我自己从未使用过它,但regmatches 真正关注的是比赛而不是捕获(两者高度相关,但略有不同)。我添加了一个额外的示例,以试图清楚地说明 regmatches() 与我的函数相比捕获的内容。`
    • 是的,我之前使用过regmatches()&lt;- 来观察零宽度匹配的效果。
    【解决方案2】:

    就解决方法而言,这是我提出的用于提取重叠匹配的方法。

    > x <- 'ACCACCACCAC'
    > m <- gregexpr('(?=([AC]C))', x, perl=T)
    > mapply(function(X) substr(x, X, X+1), m[[1]])
    [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
    

    请随意添加或评论执行此任务的更好方法。

    【讨论】:

    • 这个解决方案的问题是它只在捕获的区域总是2个字符长时才有效。一个更通用的解决方案是:
    • 糟糕。我忘了我不能把代码块放在 cmets 中。将使它成为一个单独的答案。
    【解决方案3】:

    在前瞻部分使用捕获组的stringi 解决方案:

    > stri_match_all_regex('ACCACCACCAC', '(?=([AC]C))')[[1]][,2]
    ## [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"    
    

    【讨论】:

    • 奇怪,怎么不能和stri_extract_all_regex一起工作
    • @hwnd:这是一个 0 长度匹配; (?=...)does not推进输入位置。
    • 是的,我知道这是一个零宽度匹配 =) 我猜 extract_all_regexmatch_all_regex 之间存在差异
    • 不,结果矩阵的第一列(整个匹配)只包含空字符串:)
    • 好吧,我明白你的意思了。
    【解决方案4】:

    另一种提取我过去做过的相同信息的迂回方法是将"match.length"替换为"capture.length"

    x <- c("ACCACCACCAC","ACCACCACCAC")
    m <- gregexpr('(?=([AC]C))', x, perl=TRUE)
    m <- lapply(m, function(i) {
           attr(i,"match.length") <- attr(i,"capture.length")
           i
         })
    regmatches(x,m)
    
    #[[1]]
    #[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
    #
    #[[2]]
    #[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
    

    【讨论】:

    • +1 感谢您提供额外的解决方案。我使用capture.startcapture.length 做了类似的事情。
    【解决方案5】:

    这不是正则表达式解决方案,并不能真正回答您的任何更重要的问题,但您也可以通过一次使用两个字符的子字符串然后删除不需要的 CA 元素来获得所需的结果。

    x <- 'ACCACCACCAC'
    y <- substring(x, 1:(nchar(x)-1), 2:nchar(x))
    y[y != "CA"]
    # [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
    

    【讨论】:

      【解决方案6】:

      另一个答案,基于@hwnd 自己的答案(原版不允许可变长度捕获区域),仅使用内置 R 函数:

      > x <- 'ACCACCACCAC'
      > m <- gregexpr('(?=([AC]C))', x, perl=T)[[1]]
      > start <- attr(m,"capture.start")
      > end <- attr(m,"capture.start") + attr(m,"capture.length") - 1
      > sapply(seq_along(m), function(i) substr(x, start[i], end[i]))
      [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
      

      非常丑陋,这就是存在stringr 等包的原因。

      【讨论】:

        猜你喜欢
        • 2012-12-21
        • 2014-09-15
        • 2012-02-18
        • 1970-01-01
        • 2011-11-30
        • 2023-03-20
        • 2010-09-24
        • 2017-01-31
        相关资源
        最近更新 更多