繁体   English   中英

re.finditer 和 re.findall 之间的不同行为

[英]Different behavior between re.finditer and re.findall

我正在使用以下代码:

CARRIS_REGEX=r'<th>(\d+)</th><th>([\s\w\.\-]+)</th><th>(\d+:\d+)</th><th>(\d+m)</th>'
pattern = re.compile(CARRIS_REGEX, re.UNICODE)
matches = pattern.finditer(mailbody)
findall = pattern.findall(mailbody)

但是finditer和findall是在找不同的东西。 Findall 确实找到了给定字符串中的所有匹配项。 但是finditer只找到第一个,返回一个只有一个元素的迭代器。

如何使 finditer 和 findall 的行为相同?

谢谢

我在这里无法重现。 在Python 2.7和3.1上都尝试过。

finditerfindall之间的一个区别是,前者返回正则表达式匹配对象,而另一个则返回匹配的捕获组的元组(如果没有捕获组,则返回整个匹配项)。

所以

import re
CARRIS_REGEX=r'<th>(\d+)</th><th>([\s\w\.\-]+)</th><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')

如果要从finditer获得与从findall获得相同的输出,则需要

for match in pattern.finditer(mailbody):
    print(tuple(match.groups()))

re.findall(pattern.string)

findall()返回字符串中所有不重复的模式匹配作为字符串列表。

re.finditer()

finditer()返回可调用对象

在这两个函数中,从左到右扫描字符串,并按找到的顺序返回匹配项。

您不能使它们的行为相同,因为它们是不同的。 如果您确实想从finditer创建结果列表,则可以使用列表finditer

>>> [match for match in pattern.finditer(mailbody)]
[...]

通常,使用for循环访问re.finditer返回的匹配re.finditer

>>> for match in pattern.finditer(mailbody):
...     ...

我从Python 2 **中的 正则表达式操作中获得了该示例,并且对该示例进行了详细的修改,并对它进行了详细描述。 为了说明整个示例,让我们获取字符串类型的变量调用,

text = "He was carefully disguised but captured quickly by police."

编译类型正则表达式模式为

regEX = r"\w+ly"
pattern = re.compile(regEX)

\\w mean 匹配任何单词字符(字母数字和下划线)+ mean 匹配前面的标记中的1个或多个,并且整个含义是选择任何以 ly 结尾的单词 只有两个2个单词(“仔细地”和“迅速地”)满足上述正则表达式。

在进入re.findall()re.finditer()之前 ,让我们看看re.search()Python 2. * Documentation中的含义。

扫描字符串以查找正则表达式模式产生匹配项的第一个位置,然后返回相应的MatchObject实例。 如果字符串中没有位置与模式匹配,则返回None;否则返回No。 请注意,这与在字符串中的某个点找到零长度匹配不同。

以下代码行为您提供了对re.search()的基本了解。

search = pattern.search(text)
print(search)
print(type(search))

#output
<re.Match object; span=(7, 16), match='carefully'>
<class 're.Match'>

根据Python 2. * Documentation ,它将生成类类型对象的re.MatchObject ,它具有13种受支持的方法和属性。 这个span()方法由text变量中匹配单词的起点和终点(在上面的示例中为7和16)组成。 re.search()方法仅考虑第一个匹配项,否则返回None

让我们进入一个问题,在此之前先看看re.finditer()Python 2. * Documentation中的含义。

返回一个迭代器,该迭代器在字符串的RE模式的所有非重叠匹配上产生MatchObject实例。 从左到右扫描该字符串,并以找到的顺序返回匹配项。 空匹配项包含在结果中。

接下来的代码行使您对re.finditer()有了基本的了解。

finditer = pattern.finditer(text)
print(finditer)
print(type(finditer))

#output
<callable_iterator object at 0x040BB690>
<class 'callable_iterator'>

上面的示例为我们提供了需要循环的迭代器对象 这显然不是我们想要的结果。 让我们循环finditer ,看看Iterator Objects内部有什么。

for anObject in finditer:
    print(anObject)
    print(type(anObject))
    print()

#output
<re.Match object; span=(7, 16), match='carefully'>
<class 're.Match'>

<re.Match object; span=(40, 47), match='quickly'>
<class 're.Match'>

此结果与我们之前获得的re.search()结果非常相似。 但是我们可以在上面的输出<re.Match object; span=(40, 47), match='quickly'>看到新结果<re.Match object; span=(40, 47), match='quickly'> <re.Match object; span=(40, 47), match='quickly'> 正如我之前在Python 2. * Documentation中提到的那样, re.search()扫描字符串以查找正则表达式模式产生匹配的第一个位置,re.finditer()扫描字符串以查找所有位置。正则表达式模式产生匹配项,并且比re.findall()方法返回更多详细信息。

这是re.findall()Python 2. * Documentation中的含义。

返回字符串中模式的所有非重叠匹配项,作为字符串列表。 从左到右扫描该字符串,并以找到的顺序返回匹配项。 如果该模式中存在一个或多个组,则返回一个组列表;否则,返回一个列表。 如果模式包含多个组,则这将是一个元组列表。 空匹配项包含在结果中。

让我们了解一下re.findall()中发生的情况。

findall = pattern.findall(text)
print(findall)
print(type(findall))

#output
['carefully', 'quickly']
<class 'list'>

此输出仅为我们提供text变量中匹配的单词,否则返回一个空列表 输出中的列表类似于re.MatchObject中match属性。

这是完整的代码,我在Python 3.7中尝试过。

import re

text = "He was carefully disguised but captured quickly by police."

regEX = r"\w+ly"
pattern = re.compile(regEX)

search = pattern.search(text)
print(search)
print(type(search))
print()

findall = pattern.findall(text)
print(findall)
print(type(findall))
print()

finditer = pattern.finditer(text)
print(finditer)
print(type(finditer))
print()
for anObject in finditer:
    print(anObject)
    print(type(anObject))
    print()

我来到这里试图从我的.finditer()的正则表达式结果中获取一个字符串

解决方案实际上是我需要创建至少一个组,这样才能从组 dict 中获取它

-     yield from zip(re.finditer(r"\w+", line) ...
+     yield from zip(re.finditer(r"(\w+)", line) ...
...
-     block.(miscellaneous attempts)
+     block.group(1)

从大文件中提取时使用 finditer(),因为它将返回一个迭代器 object,这有助于保存 memory 另一方面 findall() 返回一个列表。 finditer() 的提取方式与 findall() 不同。

例如:


    text_to_search = '''
    abcdefghijklmnopqurtuvwxyz
    ABCDEFGHIJKLMNOPQRSTUVWXYZ\s
    321-555-4321
    1234567890
    Ha HaHa
    MetaCharacters (Need to be escaped):
    . ^ $ * + ? { } [ ] \ | ( )
    khanafsaan11.com
    321-555-4321
    123.555.1234
    123*555*-1234
    123.555.1234
    800-555-1234
    900-555-1234
    Mr. Schafer
    Mr Smith
    Ms Davis
    Mrs. Robinson
    Mr. T
    Mr_hello
    '''
    pattern=re.compile(r'M(r|rs|s)\.? [A-Z][a-z]*')
    print(list(pattern.finditer(text_to_search))) #converted to list
    print(pattern.findall(text_to_search))

Output:


    ['r', 'r', 's', 'rs', 'r'] 
    [, , , , ]

你可以从 finditer() output 得到像 findall() 这样的 output 如下


    for obj in pattern.finditer(text_to_search):
        print(obj.group()) #group() is an attribute of re.Match object
    #ouput
    Mr. Schafer
    Mr Smith
    Ms Davis
    Mrs. Robinson
    Mr. T

finditer() 返回迭代器 object,finditer() 有助于提高 memory 基于生成器的效率。

def my_ranger(max_num):

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM