正则表达式来解析日志文件

时间:2014-08-14 19:05:15

标签: python regex

我有一个SonicWall syslog文件,格式为:

<134>id=firewall sn=C0EAE470F7D0 time="2014-08-13 04:31:27" fw=10.2.3.4 pri=6 c=1024 m=537 msg="Connection Closed" n=301541 src=172.16.1.43:50581:X0 dst=172.16.1.1:192:X0 proto=udp/192 sent=46

我正在尝试创建一个正则表达式,它将返回在=符号上拆分的元组列表。如果值包含空格,则它将具有双引号。我不关心返回的值是否返回引号,只要返回带有空格的整个值。例如,我希望时间键包含日期和时间。时间。期望的输出:

("<134>id","firewall"), ("sn","C0EAE470F7D0"), ("time", '"2014-08-13 04:31:27"')
("fw","1.2.3.4"), ("pri","6"), ... ("msg", '"Connection Closed"'), ("n", "301541")
("src","172.16.1.43:50581:X0"), ... ("sent", "46")

这是我到目前为止所做的,但遇到带双引号的字段时失败。此外,不返回在这种情况下“发送”的最后一个字段。我已经尝试了RE几个小时尝试各种组合,但只是不能让它工作。任何帮助将不胜感激。

import re
fname = "syslog.log"
with open(fname) as fp: lines = fp.read().splitlines()
q = re.compile('(.*?)=(.*?)[\s"]',re.S|re.M)
for line in lines:
    print(line)
    key_val = q.findall(line)
    print(key_val)

这是此代码返回的内容:

[('<134>id', 'firewall'), ('sn', 'C0EAE470F7D0'), ('time', ''), 
('2014-08-13 04:31:27" fw', '10.2.3.4'), ('pri', '6'),
('c', '1024'), ('m', '537'), ('msg', ''), 
('Connection Closed" n', '301541'), ('src', '172.16.1.43:50581:X0'), 
('dst', '172.16.1.1:192:X0'), ('proto', 'udp/192')]

如果使用正则表达式无法实现这一点,那么在Python 3.3中实现所需结果的最佳方法是什么?

4 个答案:

答案 0 :(得分:6)

http://regex101.com/r/wS5lX2/3

(.+?)=("[^"]*"|\S*)\s*

它做什么

  1. 将不等于等号的任何内容与等号匹配
  2. 匹配任何一个
    1. 围绕不包含引号或
    2. 的字符串的引号
    3. 没有空格的字符串
  3. 匹配空白
  4. 如果您还想删除匹配项周围的引号,则可以使用此代替

    http://regex101.com/r/wS5lX2/4

    (.+?)=(?:"(.*?)(?<!\\)"|(\S*))\s*

    它从匹配字符串中删除双引号。键将是组1,值将是组2或3.此外,它允许您在引用值中包含反斜杠 - 转义引号。

答案 1 :(得分:2)

如果您首先抓住所有令牌,然后拆分它们,这将更容易。

import re
txt = """<134>id=firewall sn=C0EAE470F7D0 time="2014-08-13 04:31:27" fw=10.2.3.4 pri=6 c=1024 m=537 msg="Connection Closed" n=301541 src=172.16.1.43:50581:X0 dst=172.16.1.1:192:X0 proto=udp/192 sent=46"""

tokens = re.findall(r'''\S+=(?:"[^"]+?")|(?:'[^']+?')|\S+=\S+''', txt)

end_result = list(map(lambda x: tuple(x.split('=')), tokens))
# output:
[('<134>id', 'firewall'), ('sn', 'C0EAE470F7D0'), ('time', '"2014-08-13 04:31:27"'), ('fw', '10.2.3.4'), ('pri', '6'), ('c', '1024'), ('m', '537'), ('msg', '"Connection Closed"'), ('n', '301541'), ('src', '172.16.1.43:50581:X0'), ('dst', '172.16.1.1:192:X0'), ('proto', 'udp/192'), ('sent', '46')]

说明:

re.compile('''
    \S+               # match one or more non-space characters
    =                 # match a literal equals
    (?:"[^"]+?")|     # match a double quotation and its contents OR
    (?:'[^']+?')      # match a single quotation and its contents
    |                 # OR
    \S+               # match one or more non-space characters
    =                 # match a literal equals
    \S+               # match one or more non-space characters
''', re.X)

答案 2 :(得分:1)

这会提供您想要的输出(并且还会删除引号):

line = """
<134>id=firewall sn=C0EAE470F7D0 time="2014-08-13 04:31:27" fw=10.2.3.4 pri=6 c=1024 m=537 msg="Connection Closed" n=301541 src=172.16.1.43:50581:X0 dst=172.16.1.1:192:X0 proto=udp/192 sent=46
"""

rx = r"""(?x)
    (\w+) =
    (?:
        " ([^"]*) "
        |
        (\S+)
    )
"""

parsed = [(id, a or b) for id, a, b in re.findall(rx, line)]
print parsed

我个人觉得字典更适合这种数据,即:

parsed = {id: a or b for id, a, b in re.findall(rx, log)}

答案 3 :(得分:1)

  

有些人在面对问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。 - jwz。

每当你在编写正则表达式时遇到问题,你应该做的第一件事就是问你是否真的需要正则表达式。毕竟,如果你不知道如何在不使用图形regexp资源管理器或让其他人帮助你的情况下编写它,你是否能够调试它,扩展它,甚至在几个月内阅读它?

您的引用规则似乎与默认的CSV引用规则相同。这意味着您可以让csv模块为您完成繁重的工作,然后只需拆分键值对,这是最简单的部分:

import csv
fname = "syslog.log"
with open(fname) as fp: 
    reader = csv.reader(fp, delimiter=' ')
    for row in reader:
        key_val = [col.split('=', 1) for col in row]
        print(key_val)