查找python正则表达式的最后一个匹配项

时间:2010-05-10 11:20:12

标签: python regex

我想匹配字符串中最后一个简单模式的出现,例如

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

但是,如果字符串非常长,则会生成大量匹配项。是否有更直接的方法来匹配“AAAA”的第二次出现,还是应该使用此解决方法?

5 个答案:

答案 0 :(得分:27)

您可以使用表示行尾字符的$

>>> s = """foo bar AAAA
foo2 AAAA bar2"""
>>> re.findall(r"\w+ AAAA \w+$", s)
['foo2 AAAA bar2']

另外,请注意list是变量的错误名称,因为它会影响内置类型。要访问列表的最后一个元素,您只需使用[-1]索引:

>>> lst = [2, 3, 4]
>>> lst[-1]
4

答案 1 :(得分:23)

您可以通过迭代所有匹配并保留最后一个匹配来避免构建列表:

for match in re.finditer(r"\w+ AAAA \w+", "foo bar AAAA foo2 AAAA bar2"):
    pass

在此之后,match保留最后一个匹配,适用于模式搜索字符串的所有组合。您可能希望先将match设置为None,因为如果没有匹配项,match将不会设置为任何值。

答案 2 :(得分:2)

我不确定你的原始正则表达式会不会给你你想要的东西。 很抱歉,如果我迟到了......但是其他人也可能觉得这很有用。

import re
p = r"AAAA(?=\s\w+)" #revised per comment from @Jerry
p2 =r"\w+ AAAA \w+"
s = "foo bar AAAA foo2 AAAA bar2"
l = re.findall(p, s)
l2 = re.findall(p2, s)
print('l: {l}'.format(l=l))

#print(f'l: {l}') is nicer, but online interpreters sometimes don't support it.
# https://www.onlinegdb.com/online_python_interpreter
#I'm using Python 3.

print('l2: {l}'.format(l=l2))
for m in re.finditer(p, s):
  print(m.span())
  #A span of (n,m) would really represent characters n to m-1 with zero based index
  #So.(8,12):
  # => (8,11: 0 based index)
  # => (9th to 12th characters conventional 1 based index)
print(re.findall(p, s)[-1])

输出:

l: ['AAAA', 'AAAA']
l2: ['bar AAAA foo2']
(8, 12)
(18, 22)   
AAAA

你在这里获得两个结果而不是原始结果的原因是(?=)特别酱。

它被称为积极向前看。 当在正则表达式评估期间找到匹配时,它不会“消耗”(即前进光标)。所以,它会在匹配后回来。

尽管正括号中有正向前瞻,但它们也充当非俘获组

因此,虽然模式匹配,但结果忽略 \w+所代表的字母数字字符的周围序列以及我的示例中的居间空间\s - 代表[ \t\n\r\f\v]。 (更多here

所以我每次都只回到AAAA。

p2在这里,代表@SDD代码的原始模式,即构成问题的人。

foo2 消耗,因为当正则表达式引擎重新开始匹配的第二次迭代时,第二个AAAA将无法匹配,因为光标已经进展太远。 p>

如果您想深入了解,我建议您查看 Moondra 的Youtube视频。

他在Python Regex上完成了一个非常全面的17部分系列文章,从here开始

这是在线Python解释器的link

答案 3 :(得分:1)

没有内置的values += portion 库功能支持从右到左的字符串解析,仅从左到右搜索输入字符串以寻找模式。

但是有PyPi regex module支持此功能。它是re标志或其内联变体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 匹配字符串开头的可选序列,任何0个或多个字符,后跟一个非单词字符((?:^[\s\S]*\W)?)。必须添加\W才能使回溯返回到非单词char,并且它必须是可选的,因为匹配可能始于字符串的开头。

请参见Python demo

答案 4 :(得分:0)

另一种快速的方法是使用searchgroup

>>> re.search('\w+ AAAA \w+$',"foo bar AAAA foo2 AAAA bar2").group(0)
'foo2 AAAA bar2'

它的作用:

  1. 它使用\w+ AAAA \w+$的模式,该模式是'AAAA'的最后一次出现,并且它们之间有旁注单词,全部使用\w+(两次),并且$(一次)。

  2. 在完成模式匹配之后,您将必须使用_sre.SRE_Match.group方法来获取_sre.SRE_Match对象的归属值,当然还要获得第零个(第一个)组,知道search仅保留一个匹配项(第零个)。

这里是regex101

以下是所有答案的时间安排(JGFMK的答案除外,因为很难):

>>> timeit.timeit(lambda: re.findall(r"\w+ AAAA \w+$", s),number=1000000) # SilentGhost
5.783595023876842
>>> timeit.timeit('import re\nfor match in re.finditer(r"\w+ AAAA \w+", "foo bar AAAA foo2 AAAA bar2"):pass',number=1000000) # tzot
5.329235373691631
>>> timeit.timeit(lambda: re.search('\w+ AAAA \w+$',"foo bar AAAA foo2 AAAA bar2").group(0),number=1000000) # mine (U9-Forward)
5.441731174121287
>>> 

我正在使用timeit模块测试所有计时,而且我正在制作number=1000000,所以它花费的时间要长得多。