0

我需要一些关于循环的帮助,或者更好的方法来解决这个问题。答案可能很明显,但我是新来的,现在感到精神障碍:我有一个看起来像这样的日志文件,我正在尝试匹配具有相同 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']
4

3 回答 3

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]
于 2013-03-19T21:22:29.037 回答
1

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

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

从上面摘录:日志文件看起来像:

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

正则表达式看起来像:

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

是这样的:

  • r => 原始字符串(在正则表达式中总是推荐)
  • \[ => 匹配方括号(否则将是一个特殊字符)
  • (\d+) => 匹配一个或多个小数 \d = 小数和 + 表示 1 个或多个
  • \] => 后跟一个右方括号
  • SERVICE NOTIFICATION: => 按顺序完全匹配这些字符。
  • (.+) => . (dot) 匹配任何字符。+ 再次表示 1 或更多

括号将结果分组。

我用你的日志文件格式做了一个简短的正则表达式。假设您上面的日志保存为 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()

正则表达式乍一看并不简单,但如果您搜索正则表达式或 re AND 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 作为其键的字典中:

导入重新正则表达式 = re.compile(r'[(\d{2}:\d{2}:\d{2}.xxx\d{3})][\s]+status[\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]

现在您可以四处玩耍并对其进行微调以适应您的需求。

于 2013-03-19T21:35:41.567 回答
0

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

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

这不是特定于文件的;这就是所有迭代器在 Python 中的工作方式。对于任何迭代器,有两种通用的方法来处理这个问题,还有一种特定于文件的解决方案。

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

一般来说,如果一个迭代器在另一个迭代器启动之前使用了大部分或全部数据,那么使用 list() 而不是 tee() 会更快。

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

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

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

最后,如果你有一个花哨的迭代器可以检查点并以某种方式恢复,你可以在内部循环之前检查点它,然后在之后立即恢复它。而且好在files恰好有这么一个东西: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)
于 2013-03-19T21:37:03.407 回答