Python正则表达式中的前一个匹配组

5

我试图捕获类似于%a%b等的字符串片段,并用一些值替换它们。此外,我希望能够通过输入%%来转义%字符。

在一个示例字符串%d%%f%x%%%g中,我想匹配%d%%f%x%%%g(即%d%x%g)。

我的正则表达式如下:

(?:[^%]|^)(?:%%)*(%[a-z])
  • (?:[^%]|^) - 匹配行的开头或与%不同的字符
  • (?:%%)* - 匹配 0 或多个 %%(转义后的 %
  • (%[a-z]) - 匹配%a%b等模式

前两个元素用于支持转义%字符。

然而,运行该正则表达式在示例字符串上时,最后一段 (%g) 没有被找到:

>>> import re
>>> pat = re.compile("(?:[^%]|^)(?:%%)*(%[a-z])")
>>> pat.findall("%d%%f%x%%%g")
['%d', '%x']

但在%%%g之前添加一个字符后,它开始正常工作:

>>> pat.findall("%d%%f%x %%%g")
['%d', '%x', '%g']

看起来在匹配到组(%[a-z])后,x没有再次与[^%]匹配。我该如何更改正则表达式以强制其再次检查上一个匹配的最后一个字符?我了解了\G,但它并没有帮助。

3个回答

3
为什么它没匹配到%g
要匹配%g,它必须在前面有%%。甚至在此之前,它必须要有一个非%字符或位于字符串开头。所以,x%%%g可以匹配成功。但是这个x在之前的匹配中(即打印%x时)已经被匹配了。
简而言之,您的正则表达式匹配存在重叠。因此,您可以使用以下解决方法。我将您的正则表达式放在(?= ... )中。
pat = re.compile("(?=(?:[^%]|^)(?:%%)*(%[a-z]))")

好的解释,虽然正则表达式不需要那么复杂。 - Tim Pietzcker
好的解释,虽然正则表达式不需要那么复杂。 - eyquem

2

你需要稍微调整一下正则表达式的构造方式:

>>> import re
>>> regex = re.compile(r"(?:[^%]|%%)*(%[a-z])")
>>> regex.findall("%d%%f%x%%%g")
['%d', '%x', '%g']

说明:

(?:      # Start of a non-capturing group:
 [^%]    # Either match any character except %
|        # or
 %%      # match an "escaped" %.
)*       # Do this any number of times.
(        # Match and capture in group 1:
 %[a-z]  # % followed by a lowercase ASCII alphanumeric
)        # End of capturing group

好的解释,虽然正则表达式不需要那么复杂。 - eyquem
你的解决方案将匹配 %%f,这是不正确的,因为 %% 应该被解释为转义 % - houen

2

我觉得你想要捕获只有在偶数个百分号之前的每个部分%x

如果是这样,模式为"(?<!%)(?:%%)*(%[a-z])"


简单的模式,虽然没有解释。 :) - eyquem
@TimPietzcker 谢谢你 :)) - eyquem
这正是我想要实现的! - houen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接