1

我有一个需要分析的文本文件。文件中的每一行都是这种形式:

7:06:32 (slbfd) IN: "lq_viz_server" aqeela@nabltas1  

7:08:21 (slbfd) UNSUPPORTED: "Slb_Internal_vlsodc" (PORT_AT_HOST_PLUS   ) Albahraj@nabwmps3  (License server system does not support this feature. (-18,327))

7:08:21 (slbfd) OUT: "OFM32" Albahraj@nabwmps3

我需要跳过时间戳和(slbfd)只保留 IN 和 OUT 的行数。此外,根据引号中的名称,如果一行以开头,我需要增加不同变量OUT的变量计数,否则减少变量计数。我将如何在 Python 中执行此操作?

4

5 回答 5

5

使用正则表达式和拆分行的其他答案将完成工作,但如果您想要一个完全可维护的解决方案,并与您一起成长,您应该构建一个语法。我喜欢pyparsing这个:

S ='''
7:06:32 (slbfd) IN: "lq_viz_server" aqeela@nabltas1  
7:08:21 (slbfd) UNSUPPORTED: "Slb_Internal_vlsodc" (PORT_AT_HOST_PLUS   ) Albahraj@nabwmps3  (License server system does not support this feature. (-18,327))
7:08:21 (slbfd) OUT: "OFM32" Albahraj@nabwmps3'''

from pyparsing import *
from collections import defaultdict

# Define the grammar
num = Word(nums)
marker = Literal(":").suppress()
timestamp = Group(num + marker + num + marker + num)
label = Literal("(slbfd)")
flag = Word(alphas)("flag") + marker
name = QuotedString(quoteChar='"')("name")

line    = timestamp + label + flag + name + restOfLine
grammar = OneOrMore(Group(line))

# Now parsing is a piece of cake!  
P = grammar.parseString(S)
counts = defaultdict(int)

for x in P:
    if x.flag=="IN": counts[x.name] += 1
    if x.flag=="OUT": counts[x.name] -= 1

for key in counts:
    print key, counts[key]

这给出了输出:

lq_viz_server 1
OFM32 -1

如果您的示例日志文件更长,这看起来会更令人印象深刻。pyparsing 解决方案的美妙之处在于能够适应未来更复杂的查询(例如,抓取和解析时间戳、提取电子邮件地址、解析错误代码......)。这个想法是您编写独立于查询的语法 - 您只需将原始文本转换为计算机友好格式,将解析实现从其使用中抽象出来。

于 2012-06-22T14:39:53.820 回答
1

我对您的规范做了一些疯狂的假设,这里有一个示例代码可以帮助您开始:

objects = {}
with open("data.txt") as data:
    for line in data:
        if "IN:" in line or "OUT:" in line:
            try:
                name = line.split("\"")[1]
            except IndexError:
                print("No double quoted name on line: {}".format(line))
                name = "PARSING_ERRORS"
            if "OUT:" in line:
                diff = 1
            else:
                diff = -1
            try:
                objects[name] += diff
            except KeyError:
                objects[name] = diff
print(objects) # for debug only, not advisable to print huge number of names
于 2012-06-22T14:31:49.890 回答
1

你有两个选择:

  1. 使用的.split()功能string(如评论中指出的)
  2. re模块用于正则表达式。

我建议使用该re模块并创建一个带有命名组的模式。

食谱:

  • 首先创建一个re.compile()包含命名组的模式
  • 对文件进行for循环以获取使用.match()od 的行
  • 在每行使用.groupdict()的创建模式对象
  • 返回匹配对象以访问您感兴趣的值
于 2012-06-22T14:29:00.730 回答
1

如果我认为文件被分成几行(我不知道是否属实),你必须split()对每一行应用函数。你会有这个:

["7:06:32", "(slbfd)", "IN:", "lq_viz_server", "aqeela@nabltas1"]  

然后我认为你必须能够应用任何逻辑来比较你需要的值。

于 2012-06-22T14:29:10.293 回答
0

在刚刚完成标准发行版的模式下,这有效:

import re
from collections import Counter
# open your file as inF...
count=Counter()
for line in inF:
    match=re.match(r'\d+:\d+:\d+ \(slbfd\) (\w+): "(\w+)"', line)
    if match:
        if match.group(1) == 'IN': count[match.group(2)]+=1
        elif match.group(1) == 'OUT': count[match.group(2)]-=1

print(count)

印刷:

Counter({'lq_viz_server': 1, 'OFM32': -1})
于 2012-06-22T15:29:28.710 回答