【问题标题】:Match parts of string that are not consecutive stretches of certain character匹配不是特定字符连续延伸的字符串部分
【发布时间】:2015-05-25 03:23:42
【问题描述】:

我有一个简单的函数,可以从字符串中产生至少 gapSize 连续 N 的所有延伸:

def get_gap_coordinates(sequence, gapSize=25):
    gapPattern = "N{"+str(gapSize)+",}"
    p = re.compile(gapPattern)
    m = p.finditer(sequence)
    for gap in m:
        start,stop = gap.span()
        yield(start,stop)

现在我想要一个完全相反的功能:匹配所有不是至少 gapSize N 的连续延伸的字符。这些拉伸可以出现在字符串中任何给定数字的位置(开头、中间和结尾)。

我已经查看了环视并尝试了

(?!N{25,}).*

但这并不能满足我的需要。 非常感谢任何帮助!

编辑: 例如:一个序列 NNNNNNACTGACGTNNNACTGACNNNNN 应该匹配 ACTGACGTNNNACTGAC 的 gapSize=5 和 ACTGACGT & ACTGAC 的 gapSize = 3。

【问题讨论】:

  • 您能发布一个包含您要匹配的字符的示例短语吗?
  • 请不要将问题的标签放入标题中。你有标签部分。
  • 是的。这不是短语,而是 DNA 序列。例如:NNNNNNNNNNNNNNNNNNNNNNNNNNNACTGTAGTGANNNNNACGTGTGTGTGTG 我想匹配ACGTGTGTGTGTGACGTGTGTGTGTGTGTGTAC。但是,N 可能在任何地方
  • 所以你基本上想匹配任何没有 N 的组?
  • @lfk:请将这些示例编辑到问题中。至于解决方案,你可以用N{<gapSize>,}拆分输入。

标签: python regex regex-negation


【解决方案1】:

所以这里有一个 pure 正则表达式解决方案,这似乎是您想要的,但我想知道是否真的有更好的方法来做到这一点。当我想出替代方案时,我会添加它们。我使用了几个在线正则表达式工具以及在 shell 中玩耍。

One of the tools 有一个漂亮的正则表达式图形,并且可以生成 SO 答案代码:正则表达式(间隔为 10)是:

^.*?(?=N{10})|(?<=N{10})[^N].*?(?=N{10})|(?<=N{10})[^N].*?$

用法:

s = 'NAANANNNNNNNNNNBBBBNNNCCNNNNNNNNNNDDDDN'
def foo(s, gapSize = 25):
    '''yields non-gap items (re.match objects) in s or
       if gaps are not present raises StopIteration immediately
    '''
    # beginning of string and followed by a 'gap' OR
    # preceded a 'gap' and followed by a 'gap' OR
    # preceded a 'gap' and followed by end of string
    pattern = r'^.*?(?=N{{{}}})|(?<=N{{{}}})[^N].*?(?=N{{{}}})|(?<=N{{{}}})[^N].*?$'
    pattern = pattern.format(gapSize, gapSize, gapSize, gapSize)
    for match in re.finditer(pattern, s):
        #yield match.span()
        yield match

for match in foo(s, 10):
    print match.span(), match.group()

'''
>>> 
(0, 5) NAANA
(15, 24) BBBBNNNCC
(34, 39) DDDDN
>>>
'''

因此,如果您稍微考虑一下,就会发现 gap 的开头是 non-gap 的结尾,反之亦然。因此,使用简单的正则表达式:遍历间隙,向循环添加逻辑以跟踪 non-gap 跨度和yield 跨度。 (我的占位符变量名可能会改进)

s = 'NAANANNNNNNNNNNBBBBNNNCCNNNNNNNNNNDDDDN'
def bar(s, n):
    '''Yields the span of non-gap items in s or
       immediately raises StopIteration if gaps are not present.
    '''
    gap = r'N{{{},}}'.format(n)
    # initialize the placeholders
    previous_start = 0
    end = len(s)
    for match in re.finditer(gap, s):
        start, end = match.span()
        if start == 0:
            previous_start = end
            continue
        end = start
        yield previous_start, end
        previous_start = match.end()
    if end != len(s):
        yield previous_start, len(s)

用法

for start, end in bar(s, 4):
    print (start, end), s[start:end]

'''
>>>
(0, 5) NAANA
(15, 24) BBBBNNNCC
(34, 39) DDDDN
>>>
''' 

【讨论】:

    【解决方案2】:

    负前瞻似乎可以正常工作。例如。对于间隙大小 3,正则表达式为:

    N{3,}?([^N](?:(?!N{3,}?).)*) 
    

    试试here

    import re
    
    def get_gap_coordinates(sequence, gapSize=25):
        gapPattern = "N{%s,}?([^N](?:(?!N{%s,}?).)*)" % (gapSize, gapSize)
        p = re.compile(gapPattern)
        m = p.finditer(sequence)
        for gap in m:
            start,stop = gap.start(1), gap.end(1)
            yield(start,stop)
    
    
    for x in get_gap_coordinates('NNNNNNACTGACGTNNNACTGACNNNNN', 3):
        print x
    

    警告:如果字符串不是以“N”序列开头,则该字符串的开头可能无法很好地匹配。但是你总是可以从左边用间隙大小乘以'N'来填充字符串。

    【讨论】:

    • 谢谢,我一直在寻找这样的东西!除了填充之外,你能想出任何方法来处理初始 N 吗?
    • 我认为这个可以完成工作(例如 gap-size 3):((?:^N{0,2})?[^N](?&lt;!N{3})(?:(?!N{3}?).)*) 一般情况是:((?:^N{0,%s})?[^N](?&lt;!N{%s})(?:(?!N{%s}?).)*) %(gapSize - 1, gapSize, gapSize) 在这种情况下,字符串的开头是用第一个显式处理的非捕获组,则有一个负面的后视。
    【解决方案3】:

    我想过用正则表达式直接匹配想要的块,但没有想到什么好东西。我认为最好继续寻找间隙并简单地使用间隙坐标来获得良好的块坐标。我的意思是,它们基本上是一样的,对吧?间隙停止是块开始,间隙开始是块停止。

    def get_block_coordinates(sequence, gapSize=25):
        gapPattern = "N{"+str(gapSize)+",}"
        p = re.compile(gapPattern)
        m = p.finditer(sequence)
        prevStop = 0
        for gap in m:
            start,stop = gap.span()
            if start:
                yield(prevStop,start)
            prevStop = stop
        if prevStop < len(sequence):
            yield(prevStop,len(sequence))
    

    【讨论】:

      【解决方案4】:

      我认为你可以这样做:

      gapPattern = "(N{"+str(gapSize)+",})"
      p = re.compile(gapPattern)
      i = 0
      for s in re.split(p, sequence):
          if not re.match(p, s):
              yield i
          i += len(s)
      

      这将根据re.split 函数生成一系列偏移到不是gap_size "N" 字符的子字符串。

      【讨论】:

      • 感谢 Misandrist,但我只想要匹配部分的坐标,而不是实际的拆分序列本身。另外,我对如何用正则表达式解决它很感兴趣
      • 如果你用 re.split 和一个匹配组分割它们,你可以通过使用序列分割返回的长度来跟踪位置。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 2012-06-15
      • 2019-05-01
      • 2019-08-01
      • 1970-01-01
      • 2019-10-18
      • 1970-01-01
      相关资源
      最近更新 更多