0


我正在使用以下正则表达式:
((FFD8FF).+?((FFD9)(?:(?!FFD8).)*))

我需要使用正则表达式执行以下操作:

  • 寻找FFD8FF
  • 找到下一个FFD9之前的最后一个FFD8FF
  • 最后停止,FFD9之后不包含任何内容
  • 除了在最后一次 FFD9 之后找到并保留任何垃圾之外,我所拥有的可以满足我的需要。我怎样才能让它跳回最后FFD9

    这是我用这个表达式搜索的字符串:

    asdfasdfasasdaFFD8FFasdfalsjdflajsdfljasdfasdfasdfasdfFFD9asdflasdflasdfFFD9asdfasdfFFD8FFasdfalsjdflajsdfljasdfasdfasdfasdfFFD9

    非常感谢你的帮助。

    更多信息:

    我有一个需要搜索的开始值和结束值列表(FFD8FF 和 FFD9 只是一对)。它们在一个列表中。因此,我使用 r.compile 在 for 循环中动态创建表达式,该循环遍历不同的值。我有以下代码,但它返回 0 个匹配项:

    regExp = re.compile("FD8FF(?:[^F]|F(?!FD8FF))*FFD9") matchObj = re.findall(regExp, contents)

    在上面的代码中,我只是尝试使用普通的正则表达式,甚至没有从列表中获取值(看起来像这样):

    regExp = re.compile(typeItem[0] + "(?:[^" + typeItem[0][0] + "]|" + typeItem[0][0] + "(?!" + typeItem[0] + "))*" + typeItem[1])

    任何其他想法为什么没有任何匹配?

    编辑:

    我发现我忘了包括标志。现在包含标志以忽略大小写和多行。我现在有

    regExp = re.compile(typeItem[0] + "(?:[^" + typeItem[0][0] + "]|" + typeItem[0][0] + "(?!" + typeItem[0] + "))*" + typeItem[1],re.M|re.I)

    虽然现在我遇到了内存错误。有什么办法可以提高效率吗?我正在使用表达式搜索数十万行(使用findall上面的表达式)

    4

    3 回答 3

    3

    一个简单的方法是使用这个:

    FFD8FF(?:[^F]|F(?!FD8FF))*FFD9
    

    解释:

    FFD8FF
    (?:     # this group describe the allowed content between the "anchors" 
        [^F]        # all that is not a "F"
      |             # OR
        F(?!FD8FF)  # a "F" not followed by "FD8FF"
    )*              # repeat (greedy)
    FFD9            # until the last FFD9 before FFD8FF
    

    即使对组使用贪婪量词,正则表达式引擎也会回溯以找到最后一个“FFD9”子字符串。

    如果要确保存在 FFD8FF,可以在模式的末尾添加前瞻:

    FFD8FF(?:[^F]|F(?!FD8FF))*FFD9(?=.*?FFD8FF)
    

    您可以通过模拟一个原子组来优化此模式,该原子组将限制回溯并允许在组内使用量词:

    FFD8FF(?:(?=([^F]+|F(?!FD8FF)))\1)*FFD9
    

    这个技巧利用了一个事实,即一旦到达右括号,前瞻的内容自然是原子的。因此,如果您将一个组包含在一个前瞻中并在其中包含一个捕获组,则只需将反向引用放在后面即可获得“原子”(不可分割的子字符串)。当正则表达式引擎需要回溯时,它将逐个原子地回溯,而不是逐个字符地回溯,这要快得多。

    如果您在此技巧之前需要一个捕获组,请不要忘记更新反向引用的数量,示例:

    (FFD8FF(?:(?=([^F]+|F(?!FD8FF)))\2)*FFD9)
    
    (FFD8FF((?:(?=([^F]+|F(?!FD8FF)))\3)*)FFD9)
    

    工作示例:

    >>> import re
    >>> yourstr = 'asdfasdfasasdaFFD8FFasdfalsjdflajsdfljasdfasdfasdfasdfFFD9asdflasdflasdfFFD9asdfasdfFFD8FFasdfalsjdflajsdfljasdfasdfasdfasdfFFD9'
    >>> p = re.compile(r'(FFD8FF((?:(?=([^F]+|F(?!FD8FF)))\3)*)FFD9)(?=.*?FFD8FF)')
    >>> re.findall(p, yourstr)
    [('FFD8FFasdfalsjdflajsdfljasdfasdfasdfasdfFFD9asdflasdflasdfFFD9', 'asdfalsjdflajsdfljasdfasdfasdfasdfFFD9asdflasdflasdf', 'D9asdflasdflasdf')]
    

    变体:

    (FFD8FF((?:(?=(F(?!FD8FF)[^F]*|[^F]+))\3)*)FFD9)(?=.*?FFD8FF)
    
    于 2014-09-28T21:21:42.720 回答
    1

    由于您的应用程序架构并不局限于一个正则表达式,因此将其分解为几个步骤:

    1. 您想以从每个 开始的单位分解文本FFD8FFFFD8FF只需使用在下一个: 之前结束的非贪婪搜索re.findall(r"FFD8FF.*?(?=FFD8FF)", contents)。(这使用了前瞻,在我看来它被过度使用了;但它可以让你为下一个字符串保存最终的 FFD8FF。)

    2. 然后,您想要修剪每个这样的字符串,使其在最后一个 FFD9. 最简单的方法是贪婪搜索: re.search(r"^.*FFD9", part). 像这样:

      for part in re.findall(r"FFD8FF.*?(?=FFD8FF)", contents):
          print(re.search(r"^.*FFD9", part).group(0))
      

    简单、可维护且高效。

    于 2014-09-28T22:25:09.430 回答
    0

    我会这样做:

    >>> re.search(r'((FFD8FF).+?(FFD9))(?:((?!FFD9).)+FFD8FF)', s).groups()
    ('FFD8FFasdfalsjdflajsdfljasdfasdfasdfasdfFFD9asdflasdflasdfFFD9',
     'FFD8FF',
     'FFD9',
     'f')
    

    第二部分仅搜索不包含以 .FFD9结尾的字符串FFD8FF

    它包括您的搜索组件,因此您仍然可以在您的正则表达式中替换它们。但是对于像这样相当复杂的事情,我会避免使用正则表达式。

    顺便说一句,感谢您发布高质量的正则表达式问题,而不是通常的垃圾邮件。

    于 2014-09-28T21:59:51.470 回答