Python 搜索日志,在匹配前后输出行

Python 搜索日志,在匹配前后输出行,python,list,slice,Python,List,Slice,我正在尝试制作一个脚本,让我搜索文件夹中的所有文本文件以查找字符串,并在我要查找的字符串所在的行之前和之后编写一个可选的行数 我的问题是,当我在slice方法中放入一个变量时,我只得到匹配前的行数。当我用纯数字([1:6])进行测试时,它是有效的 我错过了什么 我们也非常感谢您提出的任何改进建议 我正在查找的内容(数据文件): 要写入结果文件的内容: 我正在搜索的文本: 代码 import os search_folder = r'E:\stash\Logs' datafile = r'

我正在尝试制作一个脚本,让我搜索文件夹中的所有文本文件以查找字符串,并在我要查找的字符串所在的行之前和之后编写一个可选的行数

我的问题是,当我在slice方法中放入一个变量时,我只得到匹配前的行数。当我用纯数字([1:6])进行测试时,它是有效的

我错过了什么

我们也非常感谢您提出的任何改进建议


我正在查找的内容(数据文件):

要写入结果文件的内容:

我正在搜索的文本:


代码

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