Python正则中获取前一个分组
我想捕捉一些看起来像 %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 个回答
2
看起来你想要找到每个前面有偶数个%
的部分%x
。
如果是这样的话,使用的模式是"(?<!%)(?:%%)*(%[a-z])"
。
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
3
为什么没有选择 %g
呢?
要选择 %g
,前面必须有 %%
。而在这之前,必须有一个不是 %
的字符,或者它要在字符串的开头。所以,像 x%%%g
这样的字符串是可以匹配到的。但是,这里的 x
是在之前的匹配中选出来的(也就是当打印 %x
的时候)。
简单来说,你的正则表达式匹配出现了重叠。所以你可以用下面这个方法来解决这个问题。我把你的正则表达式放在了 (?= ... )
里面。
pat = re.compile("(?=(?:[^%]|^)(?:%%)*(%[a-z]))")