返回日志文件中的所有匹配行

时间:2013-03-19 21:02:33

标签: python loops pattern-matching python-2.4

我需要一些关于循环的帮助,或者更好的方法来解决这个问题。答案可能是显而易见的,但我现在是新来的,现在感觉精神障碍:我有一个看起来像这样的日志文件,我试图匹配所有具有相同ID的行:所以我可以稍后比较值匹配的ID。我能够匹配第一行,但后来我的循环似乎终止。我不确定我做错了什么,或者是否有一个更好的方法。非常感谢任何帮助!

一些注意事项:

  • 当我分割线条时,XYZ ID列在第[2]行编入索引,其中len(line)== 11。
  • 我正在尝试遍历文件,并为每一行创建一个内部循环,扫描文件的其余行以找到“匹配”。
  • 如果找到匹配项,我想返回此项,以便我可以比较值
  • 问题是我的代码似乎在找到第一个匹配后中断,因此只返回找到的第一个匹配

下面是我的代码和我正在使用的日志文件的示例(包括一些编辑的字符串只是为了保持一些业务数据私有)。实际的日志文件包含逗号,在我粘贴到此论坛之前删除了逗号:

f = open('t.log','r')
for line in f:
    aline = line.replace(',','').split()
    if len(aline)==11:
        for line in f:
            bline = line.replace(',','').split()
            if len(bline)==11 and aline[2]==bline[2]:
                print 'a: ', aline
                print 'b: ', bline

#t.log

[13:40:19.xxx009] status    -------             
[13:40:19.xxx013] status    XYZ -4  -5675.36     quote  449.70/- 449.78 avg 1418.84 -7474.48       0.134     -55.630    -395.148    
[13:40:19.xxx021] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16
[13:40:19.xxx024] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70
[13:40:19.xxx027] status    XYZ  ID:22P0099xxx0 10  -17.18   quote:    1.86/   1.90  avg:   -1.72    1.42
[13:40:19.xxx029] status    XYZ  ID:22C00995xxx 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70
[13:40:19.xxx031] status    XYZ  ID:22P00995xxx 2   9.66     quote:    3.30/   3.40  avg:    4.83   16.26
[13:40:19.xxx535] status    total xx5.52                

[13:41:20.xxx688] status    -------             
[13:41:20.xxx691] status    XYZ -4  -5675.36     quote  449.83/- 449.99 avg 1418.84 -7475.32      -0.374    -213.006     -39.391    
[13:41:20.xxx701] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.96/   1.00  avg:   -0.98   -0.08
[13:41:20.xxx704] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.65/  11.90  avg:  -13.20    2.60
[13:41:20.xxx708] status    XYZ  ID:22P0099xxx0 10  -17.18   quote:    1.83/   1.87  avg:   -1.72    1.12
[13:41:20.xxx712] status    XYZ  ID:22C00995xxx 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70
[13:41:20.xxx716] status    XYZ  ID:22P00995xxx 2   9.66     quote:    3.30/   3.35  avg:    4.83   16.26
[13:41:20.xxx718] status    XYZ  ID:22C0095xxx0 -10 35.6     quote:    5.40/   5.50  avg:   -3.56  -19.40
[13:41:20.001362] status    total xx6.68    

Result:    
$ python pnlcomp.py
    a:  ['[13:40:19.000021]', 'statusAAPL', '130322P00435000', '-4', '3.92', 'quote:', '0.98/', '1.02', 'avg:', '-0.98', '-0.16']
    b:  ['[13:41:20.000701]', 'statusAAPL', '130322P00435000', '-4', '3.92', 'quote:', '0.96/', '1.00', 'avg:', '-0.98', '-0.08']

3 个答案:

答案 0 :(得分:1)

您可以使用过滤器功能获取包含“ID”的任何行。

file = open('t.log', 'r')
result = filter(lambda s: "ID" in s, file)

你也可以使用列表理解:

file = open('t.log', 'r')
result = [s for s in file if 'ID' in s]

答案 1 :(得分:1)

你可能应该使用正则表达式(也称为正则表达式)。 Python有re模块,它实现了python的正则表达式。

请将此作为查看方向的示例:stackoverflow question finding multiple matches in a string

以上摘录: 日志文件如下所示:

[1242248375] SERVICE ALERT: myhostname.com;DNS: Recursive;CRITICAL

正则表达式看起来像:

regexp = re.compile(r'\[(\d+)\] SERVICE NOTIFICATION: (.+)')

是这样的:

  • r =>原始字符串(总是在正则表达式中推荐)
  • \ [=>匹配方括号(否则将是一个特殊字符)
  • (\ d +)=>匹配一个或多个小数\ d =小数,+为1或更多
  • \] =>然后是一个结束的方括号
  • 服务通知:=>正好按顺序匹配这些字符。
  • (。+)=>这个。 (点)匹配任何字符。再次,+表示1或更多

Parantheses对结果进行分组。

我做了一个简短的正则表达式,以你的日志文件格式开始。假设您从上面的日志保存为log.txt。

import re
regexp = re.compile(r'\[(\d{2}:\d{2}:\d{2}\.xxx\d{3})\][\s]+status[\s]+XYZ[\s]+ID:([0-9A-Zx]+)(.+)')

f = open("log.txt", "r")
for line in f.readlines():
    print line
    m = re.match(regexp, line)
    #print m
    if m:
        print m.groups()

乍一看,正则表达式并不容易看起来或直截了当,但如果你搜索正则表达式或重新运行和python,你会发现有用的例子。

为我推出这个:

[13:40:19.xxx021] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16

('13:40:19.xxx021', '22P00935xxx', ' -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16')
[13:40:19.xxx024] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70

('13:40:19.xxx024', '22C0099xxx0', ' -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70')
[13:40:19.xxx027] status    XYZ  ID:22P0099xxx0 10  -17.18   quote:    1.86/   1.90  avg:   -1.72    1.42

('13:40:19.xxx027', '22P0099xxx0', ' 10  -17.18   quote:    1.86/   1.90  avg:   -1.72    1.42')
[13:40:19.xxx029] status    XYZ  ID:22C00995xxx 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70

('13:40:19.xxx029', '22C00995xxx', ' 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70')
[13:40:19.xxx031] status    XYZ  ID:22P00995xxx 2   9.66     quote:    3.30/   3.40  avg:    4.83   16.26
('13:40:19.xxx031', '22P00995xxx', ' 2   9.66     quote:    3.30/   3.40  avg:    4.83   16.26')

每隔一行是输出,它是包含匹配组的列表。

如果您将其添加到上面的程序中:

print "ID is : ", m.groups()[1]

输出是:

[13:40:19.xxx021] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16

ID is :  22P00935xxx

[13:40:19.xxx024] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70

ID is :  22C0099xxx0

哪个与您要比较的ID相匹配。只需稍微玩一下即可获得你真正想要的效果。

最后的例子 捕获ID,测试它是否已存在,并将匹配的行添加到以te ID作为其键的字典中:

导入重新 regexp = re.compile(r'[(\ d {2}:\ d {2}:\ d {2} .xxx \ d {3})] [\ s] +状态[\ s] + XYZ [\ S] + ID:([0-9A-ZX] +)(+)')

res = {}

f = open("log.txt", "r")
for line in f.readlines():
    print line
    m = re.match(regexp, line)  
    if m:
        print m.groups()
        id = m.groups()[1]
        if id in res:
            #print "added to existing ID"
            res[id].append([m.groups()[0], m.groups()[2]])
        else:
            #print "new ID"
            res[id] = [m.groups()[0], m.groups()[2]]

for id in res:
    print "ID: ", id
    print res[id]

现在,您可以四处游戏并对其进行微调以使其适应您的需求。

答案 2 :(得分:0)

这可能不是解决问题的最佳方法,但如果您想知道如何使其发挥作用:

这里的问题是你的内部for line in f:循环消耗了文件的其余部分 - 所以当你回到外部循环时,没有什么可读的。 (还有第二个问题:当我在您的数据上运行代码时,len(aline)总是 12 ,而不是 11 。但这是一个微不足道的修复。)

这不是特定于文件;这是所有迭代器在Python中的工作方式。对于任何迭代器,有两种常规方法可以处理这种情况,另外还有一种特定于文件的解决方案。

首先,itertools.tee。这需要一个迭代器,并返回两个迭代器,每个迭代器都可以独立进行。如果它们不同步,显然必须使用一些存储来处理事情,这就是文档说明这一点的原因:

  

通常,如果一个迭代器在另一个迭代器启动之前使用大部分或全部数据,则使用list()而不是tee()会更快。

这是另一种选择:将整个迭代器读入list,这样就可以遍历切片。

这显然是其中一个迭代器使用大部分数据而另一个迭代等待的情况之一。例如,第一次通过内部循环,您在外部循环读取第1行之前读取1-20000行。因此,list是更好的选择。所以:

f = open('t.log','r')
contents = list(f)
f.close()
for idx, line in enumerate(contents):
    aline = line.replace(',','').split()
    if len(aline)==11:
        for line in contents[idx+1:]:
            bline = line.replace(',','').split()
            if len(bline)==11 and aline[2]==bline[2]:
                print 'a: ', aline
                print 'b: ', bline

最后,如果你有一个可以通过某种方式检查点和恢复的花式迭代器,你可以在内循环之前检查它,然后立即恢复它。幸运的是,文件碰巧有这样的事情:tell返回当前文件位置,seek跳转到指定位置。 (有一个很大的警告说“如果文件是以文本模式打开的(没有'b'),只有tell()返回的偏移是合法的。”但这没关系;你只使用了返回的偏移量tell这里。)

所以:

f = open('t.log','r')
for line in f:
    aline = line.replace(',','').split()
    if len(aline)==11:
        pos = f.tell()
        for line in f:
            bline = line.replace(',','').split()
            if len(bline)==11 and aline[2]==bline[2]:
                print 'a: ', aline
                print 'b: ', bline
        f.seek(pos)