在python中,有没有办法让re.finditer将文件作为输入而不是字符串?

时间:2012-06-20 20:34:37

标签: python regex file-io

假设我有一个非常大的文件foo.txt,我希望在找到正则表达式时迭代它。目前我这样做:

f = open('foo.txt')
s = f.read()
f.close()
for m in re.finditer(regex, s):
    doSomething()

有没有办法在不必将整个文件存储在内存中的情况下执行此操作?

注意:逐行读取文件不是一个选项,因为正则表达式可能跨越多行。

更新:如果可能的话,我还希望与stdin合作。

更新:我正在考虑以某种方式使用自定义文件包装器模拟字符串对象,但我不确定正则表达式函数是否会接受自定义的类似字符串的对象。

4 个答案:

答案 0 :(得分:5)

您必须以chunk方式读取文件,使用重叠以允许表达式的最大可能长度,或者使用mmapped文件,这几乎/就像使用流一样好:{{3 }}

更新到您的更新: 考虑到stdin不是一个文件,它只是表现得很像一个文件描述符等等。它是一个posix流。如果你不清楚差异,做一些谷歌搜索。操作系统无法mmap它,因此python不能。

还要考虑你正在做的事情可能是一个不适合使用正则表达式的东西。正则表达式非常适合捕获小东西,比如解析连接字符串,日志条目,csv数据等等。它们不是解析大量数据的好工具。这是设计的。你可能最好写一个自定义解析器。

过去的一些智慧之词: https://docs.python.org/library/mmap.html

答案 1 :(得分:5)

如果可以将正则表达式可以跨越的行数限制为某个合理的数量,则可以使用collections.deque在文件上创建滚动窗口,并在内存中仅保留该行数。 / p>

from collections import deque

def textwindow(filename, numlines):
    with open(filename) as f:
        window   = deque((f.readline() for i in xrange(numlines)), maxlen=numlines)
        nextline = True
        while nextline:
            text = "".join(window)
            yield text
            nextline = f.readline()
            window.append(nextline)

 for text in textwindow("bigfile.txt", 10):
     # test to see whether your regex matches and do something

答案 2 :(得分:0)

也许你可以编写一个函数,在文件一次产生一行(读一行)并在其上调用re.finditer,直到它产生一个EOF信号。

答案 3 :(得分:0)

这是另一个解决方案,使用内部文本缓冲区逐步生成找到的匹配项,而不将整个文件加载到内存中。

这个缓冲区就像文件文本中的“滑动窗口”一样,向前移动,同时产生匹配。

由于文件内容是由块加载的,这意味着此解决方案也适用于多行正则表达式。

def find_chunked(fileobj, regex, *, chunk_size=4096):
    buffer = ""

    while 1:
        text = fileobj.read(chunk_size)
        buffer += text
        matches = list(regex.finditer(buffer))

        # End of file, search through remaining final buffer and exit
        if not text:
            yield from matches
            break

        # Yield found matches except the last one which is maybe 
        # incomplete because of the chunk cut (think about '.*')
        if len(matches) > 1:
            end = matches[-2].end()
            buffer = buffer[end:]
            yield from matches[:-1]

但是,请注意,如果根本找不到匹配项,最终可能会将整个文件加载到内存中,因此如果您确信文件多次包含正则表达式模式,则最好使用此函数。