使用Python正则表达式找到最后一个匹配项
我想在一个字符串中找到某个简单模式最后出现的地方,比如:
list = re.findall(r"\w+ AAAA \w+", "foo bar AAAA foo2 AAAA bar2")
print "last match: ", list[len(list)-1]
不过,如果这个字符串非常长,就会生成一大堆匹配的结果。有没有更直接的方法来找到“ AAAA ”的第二次出现,还是说我应该使用这个变通方法呢?
5 个回答
没有内置的 re
库功能可以支持从右到左的字符串解析,输入的字符串只能从左到右搜索模式。
不过,有一个 PyPi 的 regex 模块 支持这个功能。它有一个 regex.REVERSE
标志,或者它的内联变体 (?r)
:
s="foo bar AAAA foo2 AAAA bar2"
print(regex.search(r"(?r)\w+ AAAA \w+$", s).group())
# => foo2 AAAA bar2
使用 re
模块,有一种快速到达字符串末尾的方法,使用 ^[\s\S]*
这个构造,让回溯找到你想要捕获的模式并放入一个单独的组中。不过,回溯可能会吞掉匹配的一部分(因为一旦所有后续模式匹配,它就会停止提供更多文本),如果文本太大而没有匹配,回溯可能会变得非常糟糕。只有在你的输入字符串总是匹配,或者它很短且自定义模式不太依赖回溯时,才可以使用这个技巧:
print(re.search(r"(?:^[\s\S]*\W)?(\w+ AAAA \w+)$", s).group(1))
# => foo2 AAAA bar2
这里,(?:^[\s\S]*\W)?
匹配一个可选的序列,包含字符串的开始,后面跟着任意0个或多个字符,再接一个非单词字符 (\W
)。加上 \W
是必要的,这样回溯才能回到非单词字符,并且它必须是可选的,因为匹配可能从字符串的开始处开始。
可以查看这个 Python 示例。
你可以通过遍历所有匹配项,只保留最后一个匹配,来避免创建一个列表:
def match_last(orig_string, re_prefix, re_suffix):
# first use positive-lookahead for the regex suffix
re_lookahead= re.compile(f"{re_prefix}(?={re_suffix})")
match= None
# then keep the last match
for match in re_lookahead.finditer(orig_string):
pass
if match:
# now we return the proper match
# first compile the proper regex…
re_complete= re.compile(re_prefix + re_suffix)
# …because the known start offset of the last match
# can be supplied to re_complete.match
return re_complete.match(orig_string, match.start())
return match
这样一来,match
就会保存最后一个匹配的结果,或者是 None
(表示没有匹配到)。
这个方法适用于所有的 模式 和 搜索字符串 的组合,只要你提供了可能重叠的正则表达式部分作为 re_suffix;在这个例子中,就是 \w+
。
>>> match_last(
"foo bar AAAA foo2 AAAA bar2",
r"\w+ AAAA ", r"\w+")
<re.Match object; span=(13, 27), match='foo2 AAAA bar2'>
你可以使用 $
来表示行尾字符:
>>> s = """foo bar AAAA
foo2 AAAA bar2"""
>>> re.findall(r"\w+ AAAA \w+$", s)
['foo2 AAAA bar2']
另外,注意一下,list
这个名字不太好,因为它会覆盖掉 Python 自带的类型。要访问列表中的最后一个元素,你可以直接用 [-1]
这个索引:
>>> lst = [2, 3, 4]
>>> lst[-1]
4