解析一个大文本文件并提取数据,而无需多次循环-Python

解析一个大文本文件并提取数据,而无需多次循环-Python,python,for-loop,logging,big-o,Python,For Loop,Logging,Big O,我想解析一个大的文本日志文件(大约1M行)。示例如下: 2016-11-08 03:49.879阿尔法:(157)一切都很好 2016-11-08 03:49.979阿尔法:(157)这里有一个错误 2016-11-08 03:50.879伽马:(2)这里还有别的东西 2016-11-08 03:51.879德尔塔:(69)发生了什么事 我想要实现的是查找错误,然后返回与该错误相关的所有行—在本例中为alfa。问题是,当我第一次循环并找到错误,然后将alfa(157)保存为引用时,如何返回所有a

我想解析一个大的文本日志文件(大约1M行)。示例如下:

2016-11-08 03:49.879阿尔法:(157)一切都很好

2016-11-08 03:49.979阿尔法:(157)这里有一个错误

2016-11-08 03:50.879伽马:(2)这里还有别的东西

2016-11-08 03:51.879德尔塔:(69)发生了什么事

我想要实现的是查找错误,然后返回与该错误相关的所有行—在本例中为alfa。问题是,当我第一次循环并找到错误,然后将alfa(157)保存为引用时,如何返回所有alfa(157)行(即使是在错误之前发生的那些行,如示例中所示),而不再次循环通过1M行。如果有50个错误呢?这可能吗?这是O(n2)问题吗

我想使用Python:

def analyze_log(f):
    for line in f:
        (..)

您可以将错误157或任何错误中的所有行附加到同一dict键中:

log_errors = {}
...
if log_errors.has_key(error_key):
    log_errors[error_key].append(line_from_log)
else:
    log_errors[error_key] = line_from_log

PS.has_key()已从python 3中删除,请改用“in”运算符。

1M行对于现代硬件来说没有那么大,我将使用dict组装内存中的数据库。类似于:

log_database = {}
for i, line in enumerate(logfile):
    date, time, label, message = line.split(None, 3)
    log_database.setdefault(label, []).append({
        "line number": i,
        "date": date,
        "time": time,
        "message": message,
    })

我建议您构建一个管道,这样您可以在每条管线上执行多个操作。如果你想变得更有趣,你甚至可以使用协同程序构建它,然后异步并行运行

def has_errors(line):
    return True if ('alfa' in line and 'ERROR' in line) else False

def do_something(line):
    # add your processing logic
    processed = line
    return processed

errors = list()
processed = list()

with open('kwyjibo.log') as log_file:
    for line in log_file:
        if has_errors(line):
            errors.append(line)
        processed.append(do_something(line))

# contents of kwyjibo.log
# 2016-11-08 03:49.879 alfa: (157) all is good
# 2016-11-08 03:49.979 alfa: (157) there is an ERROR here
# 2016-11-08 03:50.879 gamma: (2) something else is here
# 2016-11-08 03:51.879 delta: (69) something is going on

# Output
# In [3]: errors
# Out[3]: ['2016-11-08 03:49.979 alfa: (157) there is an ERROR here\n']

# In [4]: processed
# Out[4]:
# ['2016-11-08 03:49.879 alfa: (157) all is good\n',
# '2016-11-08 03:49.979 alfa: (157) there is an ERROR here\n',
# '2016-11-08 03:50.879 gamma: (2) something else is here\n',
# '2016-11-08 03:51.879 delta: (69) something is going on\n']

dict
中对错误进行分组,其中键是日志标签,值是行列表。您可以使用该命令打印报告。您要获取的所有行是否都是连续的?@jure它们在(数字)之前是连续的,消息的长度不同。运行脚本后,我必须处理内存中的数据库吗?它会从内存中删除自己还是我必须处理它?如果你想在脚本运行后访问数据,你必须以某种方式保存它,例如,将它转储到JSON文件(或者只使用关系数据库,如
sqlite
mysql
)。脚本运行后,所有内存都会被回收。这种方法的好处是,您可以有任意多个不同的处理步骤。考虑在构建管道时使用*NIX类型的工具。这种方法的好处在于,如果通过使处理元素协同工作,然后使执行并行,从而使其并发,则可以水平扩展。您在大文件上尝试过这种方法吗?几百万行?@Always_Hungy我用这种方法处理了400万行的文件。如果存在内存、约束问题,那么您需要考虑如何处理每个处理步骤的输出,而不是将其存储在一个列表中,将其写入另一个文件。在这种情况下,我通常编写我的应用程序,以便可以并发运行,然后并行运行。