4

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

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

有没有办法做到这一点而不必将整个文件存储在内存中?

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

更新:如果可能的话,我也希望它可以使用stdin

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

4

4 回答 4

5

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

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
于 2012-06-20T20:51:54.017 回答
5

您必须逐块读取文件,重叠以允许表达式的最大可能长度,或者使用 mmapped 文件,该文件几乎/与使用流一样好:https://docs。 python.org/library/mmap.html

更新到您的更新:考虑 stdin 不是文件,它的行为很像一个文件,因为它有一个文件描述符等等。这是一个posix流。如果您不清楚差异,请进行一些谷歌搜索。操作系统无法映射它,因此 python 不能。

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

过去的一些智慧之言: http ://regex.info/blog/2006-09-15/247

于 2012-06-20T20:40:30.647 回答
0

也许你可以编写一个函数,在文件的时间产生一行(读取一行),然后调用 re.finditer 直到它产生一个 EOF 信号。

于 2012-06-20T20:37:51.043 回答
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]

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

于 2018-05-07T22:42:57.370 回答