我想匹配字符串中最后一个简单模式的出现,例如
list = re.findall(r"\w+ AAAA \w+", "foo bar AAAA foo2 AAAA bar2")
print "last match: ", list[len(list)-1]
但是,如果字符串非常长,则会生成大量匹配项。是否有更直接的方法来匹配“AAAA”的第二次出现,还是应该使用此解决方法?
答案 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)
另一种快速的方法是使用search
和group
:
>>> re.search('\w+ AAAA \w+$',"foo bar AAAA foo2 AAAA bar2").group(0)
'foo2 AAAA bar2'
它使用\w+ AAAA \w+$
的模式,该模式是'AAAA'
的最后一次出现,并且它们之间有旁注单词,全部使用\w+
(两次),并且$
(一次)。
在完成模式匹配之后,您将必须使用_sre.SRE_Match.group
方法来获取_sre.SRE_Match
对象的归属值,当然还要获得第零个(第一个)组,知道search
仅保留一个匹配项(第零个)。
>>> 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
,所以它花费的时间要长得多。