为啥使用正则表达式 finditer() 而不是 findall()

Posted

技术标签:

【中文标题】为啥使用正则表达式 finditer() 而不是 findall()【英文标题】:Why use regex finditer() rather than findall()为什么使用正则表达式 finditer() 而不是 findall() 【发布时间】:2017-01-18 04:55:12 【问题描述】:

如果findall() 足够好,使用finditer() 有什么好处? findall() 返回所有匹配项,而 finditer() 返回无法像静态列表那样直接处理的匹配对象。

例如:

import re
CARRIS_REGEX = (r'<th>(\d+)</th><th>([\s\w\.\-]+)</th>'
                r'<th>(\d+:\d+)</th><th>(\d+m)</th>')
pattern = re.compile(CARRIS_REGEX, re.UNICODE)
mailbody = open("test.txt").read()
for match in pattern.finditer(mailbody):
    print(match)
print()
for match in pattern.findall(mailbody):
    print(match)

输出:

<_sre.SRE_Match object at 0x00A63758>
<_sre.SRE_Match object at 0x00A63F98>
<_sre.SRE_Match object at 0x00A63758>
<_sre.SRE_Match object at 0x00A63F98>
<_sre.SRE_Match object at 0x00A63758>
<_sre.SRE_Match object at 0x00A63F98>
<_sre.SRE_Match object at 0x00A63758>
<_sre.SRE_Match object at 0x00A63F98>

('790', 'PR. REAL', '21:06', '04m')
('758', 'PORTAS BENFICA', '21:10', '09m')
('790', 'PR. REAL', '21:14', '13m')
('758', 'PORTAS BENFICA', '21:21', '19m')
('790', 'PR. REAL', '21:29', '28m')
('758', 'PORTAS BENFICA', '21:38', '36m')
('758', 'SETE Rios', '21:49', '47m')
('758', 'SETE RIOS', '22:09', '68m')

出于好奇,我问这个问题。

【问题讨论】:

匹配对象包含更多关于匹配的信息。 为什么使用(i for i in iterable ) 而不是[i for i in iterable]?同样正如 BrenBarn 评论的那样,您可以使用许多属性,例如 .start.end 等。使用 finditer,它基本上是课程的马匹,您想做什么,在某些情况下,您选择什么并不重要。跨度> findall 对于许多用例来说确实足够了。没有必要使用finditer,除非您想从匹配对象中获取更多详细信息,或者正在处理足够大的数据以使搜索短路或减小返回数据的大小很重要。通常不会。 非常感谢您的回答! 【参考方案1】:

有时检索所有匹配项是多余的。如果匹配的数量真的很高,您可能会冒着加载所有内容的风险。

使用迭代器或生成器是现代 Python 中的一个重要概念。话虽如此,如果您的文本很小(例如此网页),则优化是微不足道的。

这是一个关于迭代器的相关问题:Performance Advantages to Iterators?

【讨论】:

您可能会受到比性能打击更多的内存打击。【参考方案2】:

finditer() 返回一个迭代器,而findall() 返回一个数组。迭代器仅在您调用.next() 时才起作用。 for 循环知道在迭代器上调用 .next(),这意味着如果您早早从循环中调用 break,则不会执行任何后续匹配。另一方面,数组需要完全填充,这意味着必须预先找到每个匹配项。

迭代器的内存和 CPU 效率要高得多,因为它们一次只需要加载一项。如果您要匹配一个非常大的字符串(百科全书可能有数百兆字节的文本),尝试一次查找所有匹配项可能会导致浏览器在搜索时挂起并可能耗尽内存。

【讨论】:

以上是关于为啥使用正则表达式 finditer() 而不是 findall()的主要内容,如果未能解决你的问题,请参考以下文章

是否有 Python 的 re.findall/re.finditer(迭代正则表达式结果)的 Perl 等价物?

python爬虫 正则表达式 re.finditer 元字符 贪婪匹配 惰性匹配

如何使 re.finditer 只返回每行一次

python五十九课——正则表达式的拓展内容

为啥我的正则表达式组量词不起作用?

Python爬虫编程思想(34):使用findall和finditer查找每一次出现的位置