解析文本日志文件以从日志消息中提取一些数据字段

时间:2012-04-09 06:21:36

标签: python whitespace formatting

我是python的新手并坚持如何做到这一点。 我有一个非常大的文本文件大约4GB包含错误消息。文本文件中的每条消息行代表一条消息,我需要过滤掉几个列并用|替换空格字符。 示例:

input:
83b14af0-949b-71e0-18d5-0ad781020000 40ba8352-8dd2-71dc-12b8-0ad781020000 1 -1407714483 20 COLG-GRA-617-RD1.oss 1 181895426 12 oss-ap-1.oss 0 0 48 0 0 0 1307845644 1307845647 0 2 12 0 0 0  0 0 12 0 0 0  0 0 1307845918 3 OpC 6 opcecm 9 SNMPTraps 8 IBB_COLG 4 ATM0 0  0  0  69 Cisco Agent Interface Up (linkUp Trap) on interface ATM0 --Sev Normal 372 Generic: 3; Specific: 0; Enterprise: .1.3.6.1.4.1.9.1.569;
output:
83b14af0-949b-71e0-18d5-0ad781020000 | 40ba8352-8dd2-71dc-12b8-0ad781020000 | COLG-GRA-617-RD1.oss | 1307845644 | 1307845647 |1307845918 | Cisco Agent Interface Up (linkUp Trap) on interface ATM0 | Normal 372 | Generic: 3 | Specific: 0 | Enterprise: .1.3.6.1.4.1.9.1.569

我真的很感激任何帮助

谢谢

3 个答案:

答案 0 :(得分:2)

您的输入文件格式令人讨厌。我们可以在白色空间上分割输入,但是您要捕获的一些字段应该包含空格。我们可以在列号上拆分输入,但我不确定每个字符串是否总是相同的长度;似乎数字的位数可能会有所不同。所以最好的解决方案应该是正则表达式。

用于解析整行的单个正则表达式对编写和理解非常麻木。但我们可以从较短的模式中建立模式。我认为结果很容易理解。此外,如果文件格式发生变化或您要捕获的字段发生变化,我认为您可以轻松更改此内容。

请注意,我们使用Python“字符串重复”运算符*来重复较短的模式。如果我们想要识别和捕获2个单词,我们可以使用c*2重复捕获模式两次。

在所需输出的示例中,您有一些额外的空白区域。我写的图案不能捕捉任何空白区域,但如果你真的想要白色空间,你可以根据需要编辑图案。

如果您不了解正则表达式,则应阅读Python re模块的文档。简而言之,将捕获括号中包含的图案部分,其他部分将匹配但不会被捕获。 \s匹配空格,\S匹配非空格。模式中的+表示“1或更多”,*表示“0或更多”。 ^$分别匹配模式的开头和结尾。

import re

# Define patterns we want to recognize.

c = r'(\S+)\s+'  # a word we want to capture
s = r'\S+\s+'  # a word we want to skip
mesg = r'(\S.*\S)\s+--Sev\s+'  # mesg to capture; terminated by string '--Sev'
w2 = r'(\S+\s+\S+)\s+'  # two words separated by some white space
w2semi = r'(\S+\s+\S+)\s*;\s+'  # two words terminated by a semicolon
tail = r'(.*\S)\s*;'

# Join together the above patterns to make one giant pattern that parses
# the input.
s_pat = ( r'^\s*' + 
    c*2 + s*3 + c*1 + s*10 + c*2 + s*14 + c*1 + s*14 +
    mesg + w2 + w2semi*2 + tail +
    r'\s*$')

# Pre-compile the pattern for speed.
pat = re.compile(s_pat)

# Test string and the expected output result.
s_input = "83b14af0-949b-71e0-18d5-0ad781020000 40ba8352-8dd2-71dc-12b8-0ad781020000 1 -1407714483 20 COLG-GRA-617-RD1.oss 1 181895426 12 oss-ap-1.oss 0 0 48 0 0 0 1307845644 1307845647 0 2 12 0 0 0  0 0 12 0 0 0  0 0 1307845918 3 OpC 6 opcecm 9 SNMPTraps 8 IBB_COLG 4 ATM0 0  0  0  69 Cisco Agent Interface Up (linkUp Trap) on interface ATM0 --Sev Normal 372 Generic: 3; Specific: 0; Enterprise: .1.3.6.1.4.1.9.1.569;"
s_correct = "83b14af0-949b-71e0-18d5-0ad781020000|40ba8352-8dd2-71dc-12b8-0ad781020000|COLG-GRA-617-RD1.oss|1307845644|1307845647|1307845918|Cisco Agent Interface Up (linkUp Trap) on interface ATM0|Normal 372|Generic: 3|Specific: 0|Enterprise: .1.3.6.1.4.1.9.1.569"

# re.match() returns a "match group"
m = re.match(pat, s_input)
# m.groups() returns sequence of captured strings; join with '|'
s_output = '|'.join(m.groups())

# sanity check
if s_correct == s_output:
    print "excellent"
else:
    print "bogus"

# excellent.

通过编写,测试和调试模式,编写程序来实际处理文件非常简单。

# use the pattern defined above, named "pat"
with open(input_file, "r") as f_in, open(output_file, "w") as f_out:
    for line_num, line in enumerate(f_in, 1):
        try:
            m = re.match(pat, line)
            s_output = '|'.join(m.groups())
            f_out.write(s_output + '\n')
        except Exception:
            print("unable to parse line %d: %s" % (line_num, line)

这将一次读取一行文件,处理该行,并将处理过的行写入输出文件。

请注意,我在一行中使用了多个with语句。这适用于任何最近的Python,但不适用于2.5或3.0。

答案 1 :(得分:1)

对于您读入的行,使用字符串的内置replace()方法。有关字符串方法的列表,请参阅http://docs.python.org/library/stdtypes.html#string-methods

new_string = my_string.replace(' ', ' | ')

如果您还需要删除“列”,那么您可以更好地分割字符串,删除带有“slices”的列,然后加入拆分器上的列表。

cols = my_string.split(' ')
cols = cols[:2] + cols[4:8] + cols[11:]  #Just making up some arbitrary removed columns
new_string = ' | '.join(cols)

请注意,这假设您的输入始终是空格分隔的,并且您的数据不包含空格。如果您的输入数据更复杂,拆分代码会更有趣。

答案 2 :(得分:0)

如果您使用的是linux,则可以使用sed命令轻松替换字符。它会比在python中逐行读取更快,因为你的文件太大了。

sed -i 's/pattern/|/g' inputfile

上面的命令将用|。

替换所有模式字符串
相关问题