【问题标题】:Python big file parsing with rePython大文件解析与re
【发布时间】:2026-01-11 11:20:02
【问题描述】:

如何使用正则表达式解析大文件(使用re 模块),而不将整个文件加载到字符串(或内存)中?内存映射文件无济于事,因为它们的内容无法转换为某种惰性字符串。 re 模块仅支持字符串作为内容参数。

#include <boost/format.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/regex.hpp>
#include <iostream>

int main(int argc, char* argv[])
{
    boost::iostreams::mapped_file fl("BigFile.log");
    //boost::regex expr("\\w+>Time Elapsed .*?$", boost::regex::perl);
    boost::regex expr("something usefull");
    boost::match_flag_type flags = boost::match_default;
    boost::iostreams::mapped_file::iterator start, end;
    start = fl.begin();
    end = fl.end();
    boost::match_results<boost::iostreams::mapped_file::iterator> what;
    while(boost::regex_search(start, end, what, expr))
    {
        std::cout<<what[0].str()<<std::endl;
        start = what[0].second;
    }
    return 0;
}

为了展示我的要求。我使用 C++(和 boost)编写了一个简短的示例,我想在 Python 中使用。

【问题讨论】:

  • 除非你需要多行正则表达式,否则逐行解析文件。
  • 也许如果您将问题重新表述为您拥有什么以及您想要实现什么,它会给我们一个更好的机会提出建议 - 除非您坚持特定的方法。

标签: python regex file


【解决方案1】:

现在一切正常(Python 3.2.3 与 Python 2.7 在界面上有一些差异)。搜索模式应仅以 b" 为前缀以获得有效的解决方案(在 Python 3.2.3 中)。

import re
import mmap
import pprint

def ParseFile(fileName):
    f = open(fileName, "r")
    print("File opened succesfully")
    m = mmap.mmap(f.fileno(), 0, access = mmap.ACCESS_READ)
    print("File mapped succesfully")
    items = re.finditer(b"\\w+>Time Elapsed .*?\n", m)
    for item in items:
        pprint.pprint(item.group(0))

if __name__ == "__main__":
    ParseFile("testre")

【讨论】:

  • 这很简洁,因为它允许使用多行正则表达式。
【解决方案2】:

这取决于你在做什么类型的解析。

如果您正在执行的解析是逐行的,您可以使用以下命令遍历文件的行:

with open("/some/path") as f:
    for line in f:
        parse(line)

否则,您将需要通过一次读取块并解析它们来使用分块之类的东西。显然,这需要更加小心,以防您尝试匹配的内容与块边界重叠。

【讨论】:

  • 感谢我正在搜索流中的模式而不检查行边界。
【解决方案3】:

要详细说明 Julian 的解决方案,您可以通过存储和连接连续行来实现分块(如果您想执行多行正则表达式),如下所示:

list_prev_lines = []
for i in range(N):
    list_prev_lines.append(f.readline())
for line in f:
    list_prev_lines.pop(0)
    list_prev_lines.append(line)
    parse(string.join(list_prev_lines))

这将保留前 N 行的运行列表,包括当前行,然后将多行组解析为单个字符串。

【讨论】:

  • 是的,但我不知道需要多少行(通常),实际上这种情况只是将整个文件读入内存的子情况。相反,我想有一个使用内存映射文件的通用解决方案(因为易于使用和良好的效率)。