在 python 行中找到的匹配字符串后打印前几行
Print a number of previous lines after matching string found in line in python
我正在编写一个程序来解析一些日志文件。如果行中有错误代码,我需要打印前 25 行以供分析。我希望能够根据各个错误代码(而不是 25 行,15 或 35)用更多或更少的行重复这个概念。
with open(file, 'r') as input:
for line in input:
if "error code" in line:
#print previous 25 lines
我知道 Bash 中我需要的等效命令是 grep "error code" -B 25 Filename | wc -1
。我对 python 和一般编程还是新手,我知道我需要一个 for
循环,我已经尝试使用 range
函数来执行此操作,但我还没有运气不好,因为我不知道如何将范围实现到文件中。`
这是 a length limited collections.deque
的完美用例:
from collections import deque
line_history = deque(maxlen=25)
with open(file) as input:
for line in input:
if "error code" in line:
print(*line_history, line, sep='')
# Clear history so if two errors seen in close proximity, we don't
# echo some lines twice
line_history.clear()
else:
# When deque reaches 25 lines, will automatically evict oldest
line_history.append(line)
完整解释为什么我选择这种方法(如果你不在乎,请跳过):
这无法通过使用 for
/range
的 good/safe 方式解决,因为索引只有在将整个文件加载到内存中时才有意义;磁盘上的文件不知道行的开始和结束位置,因此您不能只要求 "line #357 of the file" 而不从头开始阅读以找到第 1 行到第 356 行。您最终要么反复重新读取文件,或将整个文件放入内存序列(例如 list
/tuple
)以使索引有意义。
对于日志文件,您必须假设它可能非常大(我经常处理数 GB 的日志文件),以至于将其加载到内存中会耗尽主内存,所以 slurping 不是个好主意,并且每次遇到错误时都从头开始重新读取文件几乎同样糟糕(它很慢,但我猜它确实很慢?)。基于 deque
的方法意味着您的峰值内存使用量基于文件中最长的 27 行,而不是文件总大小。
一个天真的解决方案,除了内置之外什么都没有,可以像这样简单:
with open(file) as input:
lines = tuple(input) # Slurps all lines from file
for i, line in enumerate(lines):
if "error code" in line:
print(*lines[max(i-25, 0):i], line, sep='')
但是就像我说的,这需要足够的内存来一次将整个日志文件保存在内存中,这是一件很糟糕的事情。当两个错误非常接近时,它也会重复行,因为与 deque
不同,您没有一种简单的方法来清空最近的记忆;您必须手动跟踪最后一个 print
的索引以限制您的切片。
请注意,即便如此,我也没有使用 range
; range
是很多 C 出身的人所依赖的拐杖,但它通常是 Python 中解决问题的错误方法。在 需要 索引的情况下(通常不需要),您通常也需要该值,因此基于 enumerate
的解决方案更胜一筹;大多数时候,您根本不需要索引,因此直接迭代(或与 zip
等配对迭代)是正确的解决方案。
尝试在没有任何特殊库的情况下使用 for
循环和 range
函数进行基本编码:
N = 25
with open(file, 'r') as f:
lines = f.read().splitlines()
for i, line in enumerate(lines):
if "error code" in line:
j = i-N if i>N else 0
for k in range(j,i):
print(lines[k])
以上打印前 25 行,如果总行数少于 25 行,则从第一行打印。
此外,最好避免使用 input
作为变量项,因为它是 Python 中的关键字。
我正在编写一个程序来解析一些日志文件。如果行中有错误代码,我需要打印前 25 行以供分析。我希望能够根据各个错误代码(而不是 25 行,15 或 35)用更多或更少的行重复这个概念。
with open(file, 'r') as input:
for line in input:
if "error code" in line:
#print previous 25 lines
我知道 Bash 中我需要的等效命令是 grep "error code" -B 25 Filename | wc -1
。我对 python 和一般编程还是新手,我知道我需要一个 for
循环,我已经尝试使用 range
函数来执行此操作,但我还没有运气不好,因为我不知道如何将范围实现到文件中。`
这是 a length limited collections.deque
的完美用例:
from collections import deque
line_history = deque(maxlen=25)
with open(file) as input:
for line in input:
if "error code" in line:
print(*line_history, line, sep='')
# Clear history so if two errors seen in close proximity, we don't
# echo some lines twice
line_history.clear()
else:
# When deque reaches 25 lines, will automatically evict oldest
line_history.append(line)
完整解释为什么我选择这种方法(如果你不在乎,请跳过):
这无法通过使用 for
/range
的 good/safe 方式解决,因为索引只有在将整个文件加载到内存中时才有意义;磁盘上的文件不知道行的开始和结束位置,因此您不能只要求 "line #357 of the file" 而不从头开始阅读以找到第 1 行到第 356 行。您最终要么反复重新读取文件,或将整个文件放入内存序列(例如 list
/tuple
)以使索引有意义。
对于日志文件,您必须假设它可能非常大(我经常处理数 GB 的日志文件),以至于将其加载到内存中会耗尽主内存,所以 slurping 不是个好主意,并且每次遇到错误时都从头开始重新读取文件几乎同样糟糕(它很慢,但我猜它确实很慢?)。基于 deque
的方法意味着您的峰值内存使用量基于文件中最长的 27 行,而不是文件总大小。
一个天真的解决方案,除了内置之外什么都没有,可以像这样简单:
with open(file) as input:
lines = tuple(input) # Slurps all lines from file
for i, line in enumerate(lines):
if "error code" in line:
print(*lines[max(i-25, 0):i], line, sep='')
但是就像我说的,这需要足够的内存来一次将整个日志文件保存在内存中,这是一件很糟糕的事情。当两个错误非常接近时,它也会重复行,因为与 deque
不同,您没有一种简单的方法来清空最近的记忆;您必须手动跟踪最后一个 print
的索引以限制您的切片。
请注意,即便如此,我也没有使用 range
; range
是很多 C 出身的人所依赖的拐杖,但它通常是 Python 中解决问题的错误方法。在 需要 索引的情况下(通常不需要),您通常也需要该值,因此基于 enumerate
的解决方案更胜一筹;大多数时候,您根本不需要索引,因此直接迭代(或与 zip
等配对迭代)是正确的解决方案。
尝试在没有任何特殊库的情况下使用 for
循环和 range
函数进行基本编码:
N = 25
with open(file, 'r') as f:
lines = f.read().splitlines()
for i, line in enumerate(lines):
if "error code" in line:
j = i-N if i>N else 0
for k in range(j,i):
print(lines[k])
以上打印前 25 行,如果总行数少于 25 行,则从第一行打印。
此外,最好避免使用 input
作为变量项,因为它是 Python 中的关键字。