使用Python正则表达式找到最后一个匹配项

39 投票
5 回答
66928 浏览
提问于 2025-04-15 22:32

我想在一个字符串中找到某个简单模式最后出现的地方,比如:

list = re.findall(r"\w+ AAAA \w+", "foo bar AAAA foo2 AAAA bar2")
print "last match: ", list[len(list)-1]

不过,如果这个字符串非常长,就会生成一大堆匹配的结果。有没有更直接的方法来找到“ AAAA ”的第二次出现,还是说我应该使用这个变通方法呢?

5 个回答

4

没有内置的 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 示例

34

你可以通过遍历所有匹配项,只保留最后一个匹配,来避免创建一个列表:

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'>
39

你可以使用 $ 来表示行尾字符:

>>> 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

撰写回答