Python 搜索日志,在匹配前后输出行
我正在尝试制作一个脚本,让我搜索文件夹中的所有文本文件以查找字符串,并在我要查找的字符串所在的行之前和之后编写一个可选的行数 我的问题是,当我在slice方法中放入一个变量时,我只得到匹配前的行数。当我用纯数字([1:6])进行测试时,它是有效的 我错过了什么 我们也非常感谢您提出的任何改进建议Python 搜索日志,在匹配前后输出行,python,list,slice,Python,List,Slice,我正在尝试制作一个脚本,让我搜索文件夹中的所有文本文件以查找字符串,并在我要查找的字符串所在的行之前和之后编写一个可选的行数 我的问题是,当我在slice方法中放入一个变量时,我只得到匹配前的行数。当我用纯数字([1:6])进行测试时,它是有效的 我错过了什么 我们也非常感谢您提出的任何改进建议 我正在查找的内容(数据文件): 要写入结果文件的内容: 我正在搜索的文本: 代码 import os search_folder = r'E:\stash\Logs' datafile = r'
我正在查找的内容(数据文件): 要写入结果文件的内容: 我正在搜索的文本:
代码
import os
search_folder = r'E:\stash\Logs'
datafile = r'E:\stash\variable.txt'
resultsFile = r'E:\stash\results.txt'
nbrOfLinesOver = 3
nbrOfLinesUnder = 2
# Finds all the log files in the directory that needs to be searched through
def findFiles(folder):
log_files = []
for files in os.listdir(search_folder):
log_files.append(files)
return log_files
# Finds the strings I want to search for
def searchFor(datafile):
stringToFind = open(datafile,'r')
data = stringToFind.readline()
data = str(data).split()
map(str.strip,data)
stringToFind.close()
return data
#Searches through the text files to find the strings and outputs the number of lines defined under and over the match
def findLogData(log_Files, searchForData, folderPath, resultsFile):
resultFile = open(resultsFile, "w")
lineCounter = 0
logLines = []
for file in log_Files:
datalookUp = open(folderPath + "\\" + file,'r', encoding='UTF-8')
log = datalookUp.readlines()
for line in log:
lineCounter += 1
logLines.append(str(line))
for stringToFind in searchForData:
if stringToFind in line:
slinceStart = lineCounter - nbrOfLinesOver
slinceEnd = lineCounter + nbrOfLinesUnder
resultFile.writelines(logLines[slinceStart:slinceEnd])
resultFile.close()
datalookUp.close()
FilesToSearch = findFiles(search_folder)
stringsToFind = searchFor(datafile)
findLogData(FilesToSearch,stringsToFind,search_folder,resultsFile)
编辑:我也有问题的搜索。现在,我必须把所有我想搜索的东西放在一行。当文本文件中列出了要搜索的所有字符串时,列表中也会出现“\n”。
这也是map函数的原因。这是我在论坛上找到一个建议后试图删除它时忘记删除的代码,但我无法让strip删除换行符。是的,发生这种情况的原因是
logLines
只包含包含字符串的行,之后不包含任何行(因为这些行尚未被读取)
另外,需要注意的一点是,在切片时,即使切片边界超出边界,也不会抛出错误,而是会获取范围内所有可能的元素并返回该错误。范例-
>>> lst = [1,2,3,4]
>>> lst[3:123]
[4]
您不应该将整个日志文件存储在logLines
中的内存中,而应该只存储所需的数量。另外,建议将与
一起使用,因为这样可以为您处理关闭文件的问题。示例代码-
def findLogData(log_Files, searchForData, folderPath, resultsFile):
with open(resultsFile, "w") as resultFile:
lineCounter = 0
for file in log_Files:
with open(folderPath + "\\" + file,'r', encoding='UTF-8') as datalookUp:
logLines = []
flag = False
remLines = 0
for line in log:
if remLines > 0:
resultsFile.write(line)
remLines -= 1
logLines.append(line)
if len(logLines) > nbrOfLinesOver + 1:
logLines.pop(0)
for stringToFind in searchForData:
if stringToFind in line:
resultsFile.writelines(logLines)
remLines = nbrOfLinesUnder
以下是我对这项任务的看法(简化了一点,以抓住重要的一点——在从文件读取匹配之前/之后获取x行上下文): 测试日志
1 Lorem ipsum dolor sit amet, consectetuer adipiscing
2 elit. Aenean commodo ligula eget d
3 olor. Aenean massa.
4 Cum sociis natoque 12345 penatibus et m
5 agnis dis parturient montes, nasc
6 etur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat
7 massa quis enim. Donec pede just
8 o, fringilla vel,
9 aliquet nec, vulputate eget, arcu. In enim justo,
test.py
def get_lines(file_name):
lines = None
with open(file_name, 'rb') as f:
lines = f.readlines()
return lines
def print_matches_in_file(search_str, file_name, num_lines_context=0):
"""
Will print out matching lines as well as num_lines_context before and
num_lines_context after
"""
lines = get_lines(file_name)
if lines:
num_lines = len(lines)
for idx, line in enumerate(lines):
if search_str in line:
start_line = max([0, idx - num_lines_context])
end_line = min([num_lines, idx + num_lines_context + 1])
print ''.join(lines[start_line: end_line])
print_matches_in_file("12345", "test.log", num_lines_context=2)
运行时,输出:
2 elit. Aenean commodo ligula eget d
3 olor. Aenean massa.
4 Cum sociis natoque 12345 penatibus et m
5 agnis dis parturient montes, nasc
6 etur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat
这会在搜索匹配的子字符串之前立即将整个日志文件读入内存,而匹配的子字符串可能合适,也可能不合适,具体取决于文件的大小。
logLines
似乎是多余的-只需使用log
,您不需要创建单独的列表来保存感兴趣的行
我修改了您的函数,保留了原始行的注释##
-和单个#
,以简化文件路径的构造
删除原始行后:
def findLogData(log_Files, searchForData, folderPath, resultsFile, span = (3,2)):
nbrOfLinesOver, nbrOfLinesUnder = span
with open(resultsFile, 'w') as resultFile:
for filename in log_Files:
#filename = folderPath + "\\" + file
with open(filename,'r', encoding='UTF-8') as f:
log = f.readlines()
for lineCounter, line in enumerate(log):
for stringToFind in searchForData:
if stringToFind in line:
slinceStart = min(0, lineCounter - nbrOfLinesUnder)
slinceEnd = max(len(log), lineCounter + nbrOfLinesOver + 1)
resultFile.writelines(log[slinceStart:slinceEnd])
如果搜索文件夹中的所有文件都是日志文件,则实际上不需要
findFiles()
-os.listdir()
返回一个
FilesToSearch = os.listdir(search_folder)
我可能会让FileToSearch包含每个日志文件的整个文件路径
FilesToSearch = []
for fname in os.listdir(search_folder):
FilesToSearch.append(search_folder + '\\' + fname)
或
看起来您希望使用
数据文件的第一行。我更喜欢使用上下文管理器()打开文件,以便始终关闭文件:
def searchFor(datafile):
with open(datafile,'r') as f:
data = f.readline()
data = data.split()
data = [thing.strip() for thing in data]
return data
它缺少行号行号?根据OP的例子,这是文件本身的一部分,如果是这样,它也会出现在结果文件中。如果不是,原始OP的代码也不会写行号,所以不确定OP是否真的需要。谢谢!它们相当大。从几kbs到几乎一个gig。我肯定需要对数据进行一些处理,这样我就不会将所有内容都存储在内存中。我不太明白你的代码是怎么读的,所以我必须运行它,看看会发生什么。在searchfor()
中,你没有将map
的返回值赋给任何东西。logLines
似乎是多余的-只需使用log
,您不需要创建单独的列表来保存您感兴趣的行。谢谢!我已经删除了find_文件并使用了你的建议。其他人也指出了同样的问题,使用了上下文管理器,所以我编辑了代码来使用它。我还看到其他人也在使用min和max来定义切片。当我使用它时,我会列出文件的全部内容。不仅仅是我要寻找的字符串行和前后的行数。只需使用slinceStart=lineCounter-nbrOfLinesOver就可以了。哦,还有一件事。我记得为什么我在searchFor方法中有map,它是我无法解决的问题遗留下来的代码。我无法在注释中进行大量的书写或文本格式设置,因此我将在问题帖子中编辑我的问题。@SuperKyllingen-min
和max
用于防止指定无效的索引。如果在您使用它时该功能不起作用,那么一定是其他功能出了问题-当我使用它时,它会起作用-您可以尝试打印lineCounter
,slinceStart
和slincestend
来尝试并诊断它。
def findLogData(log_Files, searchForData, folderPath, resultsFile, span = (3,2)):
nbrOfLinesOver, nbrOfLinesUnder = span
with open(resultsFile, 'w') as resultFile:
for filename in log_Files:
#filename = folderPath + "\\" + file
with open(filename,'r', encoding='UTF-8') as f:
log = f.readlines()
for lineCounter, line in enumerate(log):
for stringToFind in searchForData:
if stringToFind in line:
slinceStart = min(0, lineCounter - nbrOfLinesUnder)
slinceEnd = max(len(log), lineCounter + nbrOfLinesOver + 1)
resultFile.writelines(log[slinceStart:slinceEnd])
FilesToSearch = os.listdir(search_folder)
FilesToSearch = []
for fname in os.listdir(search_folder):
FilesToSearch.append(search_folder + '\\' + fname)
import os.path
for fname in os.listdir(search_folder):
FilesToSearch.append(os.path.join(search_folder,fname))
def searchFor(datafile):
with open(datafile,'r') as f:
data = f.readline()
data = data.split()
data = [thing.strip() for thing in data]
return data