在Python中解析键值日志
我有一个如下所示的系统日志:在Python中解析键值日志,python,Python,我有一个如下所示的系统日志: { a = 1 b = 2 c = [ x:1, y:2, z:3, ] d = 4 } 我想在Python中将其解析为一个dictionary对象,并使用=拆分键值对。同时,由[]包围的数组也被保留。我希望尽可能保持这种通用性,以便解析也可以保存一些未来的变体 到目前为止我所尝试的(代码将被编写):按“=”将每一行拆分为键值对,确定[and]开
{
a = 1
b = 2
c = [
x:1,
y:2,
z:3,
]
d = 4
}
我想在Python中将其解析为一个dictionary对象,并使用=拆分键值对。同时,由[]包围的数组也被保留。我希望尽可能保持这种通用性,以便解析也可以保存一些未来的变体
到目前为止我所尝试的(代码将被编写):按“=”将每一行拆分为键值对,确定[and]开始和结束的位置,然后按“:”将中间的行拆分为键值对。这似乎有点硬编码。。有更好的主意吗?可能有更好的答案,但我会利用您所有的字典键都处于相同的缩进级别。由于列表结构有点奇怪(它看起来像是列表和字典的交叉点),所以没有一种明显的方法可以通过新行分割、JSON加载或诸如此类的事情来实现这一点 下面是一个基于缩进级别解析键的实现:
import re
log = '''{
a = 1
b = 2
c = [
x:1,
y:2,
z:3,
]
d = 4
}'''
log_lines = log.split('\n')[1:-1] # strip bracket lines
KEY_REGEX = re.compile(r' [^ ]')
d = {}
current_pair = ''
for i, line in enumerate(log_lines):
if KEY_REGEX.match(line):
if current_pair:
key, value = current_pair.split('=')
d[key.strip()] = value.strip()
current_pair = line
else:
current_pair += line.strip()
if current_pair:
key, value = current_pair.split('=')
d[key.strip()] = value.strip()
print(d)
输出:
{'d': '4', 'c': '[x:1,y:2,z:3,]', 'a': '1', 'b': '2'}
也许有一个更好的答案,但我会利用所有字典键都处于相同缩进级别的优势。由于列表结构有点奇怪(它看起来像是列表和字典的交叉点),所以没有一种明显的方法可以通过新行分割、JSON加载或诸如此类的事情来实现这一点 下面是一个基于缩进级别解析键的实现:
import re
log = '''{
a = 1
b = 2
c = [
x:1,
y:2,
z:3,
]
d = 4
}'''
log_lines = log.split('\n')[1:-1] # strip bracket lines
KEY_REGEX = re.compile(r' [^ ]')
d = {}
current_pair = ''
for i, line in enumerate(log_lines):
if KEY_REGEX.match(line):
if current_pair:
key, value = current_pair.split('=')
d[key.strip()] = value.strip()
current_pair = line
else:
current_pair += line.strip()
if current_pair:
key, value = current_pair.split('=')
d[key.strip()] = value.strip()
print(d)
输出:
{'d': '4', 'c': '[x:1,y:2,z:3,]', 'a': '1', 'b': '2'}
这可以很容易地简化为YAML
pip安装pyyaml
,然后进行如下设置:
import string, yaml
data = """
{
a = 1
b = 2
c = [
x:1,
y:2,
z:3,
]
d = 4
}
"""
通过此设置,您可以使用以下方法解析数据:
data2 = data.replace(":", ": ").replace("=", ":").replace("[","{").replace("]","}")
lines = data2.splitlines()
for i, line in enumerate(lines):
if len(line)>0 and line[-1] in string.digits and not line.endswith(",") or i < len(lines) - 1 and line.endswith("}"):
lines[i] += ","
data3 = "\n".join(lines)
yaml.load(data3) # {'a': 1, 'b': 2, 'c': {'x': 1, 'y': 2, 'z': 3}, 'd': 4}
接下来,我们有一个for
循环。这只是负责在缺少逗号的行之后添加逗号。缺少for循环的两种情况是:
-它们在一个数值之后不存在
-他们在结束时缺席
我们使用len(line)>0和string.digits中的第[-1]行匹配第一种情况(行中的最后一个字符是数字)
使用i
匹配第二种情况。这将检查该行是否以}
结尾,并检查该行是否不是最后一行,因为YAML不允许在最后一个括号后使用逗号
循环之后,我们有:
{
a : 1,
b : 2,
c : {
x: 1,
y: 2,
z: 3,
},
d : 4,
}
这是有效的YAML。剩下的就是yaml.load
,您就有了一个pythondict
如果有什么不清楚的地方,请留下评论,我很乐意详细说明。这可以很容易地简化为YAMLpip安装pyyaml
,然后进行如下设置:
import string, yaml
data = """
{
a = 1
b = 2
c = [
x:1,
y:2,
z:3,
]
d = 4
}
"""
通过此设置,您可以使用以下方法解析数据:
data2 = data.replace(":", ": ").replace("=", ":").replace("[","{").replace("]","}")
lines = data2.splitlines()
for i, line in enumerate(lines):
if len(line)>0 and line[-1] in string.digits and not line.endswith(",") or i < len(lines) - 1 and line.endswith("}"):
lines[i] += ","
data3 = "\n".join(lines)
yaml.load(data3) # {'a': 1, 'b': 2, 'c': {'x': 1, 'y': 2, 'z': 3}, 'd': 4}
接下来,我们有一个for
循环。这只是负责在缺少逗号的行之后添加逗号。缺少for循环的两种情况是:
-它们在一个数值之后不存在
-他们在结束时缺席
我们使用len(line)>0和string.digits中的第[-1]行匹配第一种情况(行中的最后一个字符是数字)
使用i
匹配第二种情况。这将检查该行是否以}
结尾,并检查该行是否不是最后一行,因为YAML不允许在最后一个括号后使用逗号
循环之后,我们有:
{
a : 1,
b : 2,
c : {
x: 1,
y: 2,
z: 3,
},
d : 4,
}
这是有效的YAML。剩下的就是yaml.load
,您就有了一个pythondict
如果有什么不清楚的地方,请留下评论,我很乐意详细说明。我建议您熟悉一下。另外,你的键值对不是用逗号分隔,而是用换行符分隔吗?@NathanielFord,正是这种格式。你能澄清一下“保留”是什么意思吗?我建议你熟悉一下。还有,你的键值对不是用逗号分隔,而是用换行符分隔吗?@NathanielFord,就是这个格式。你能澄清一下你所说的“保留”是什么意思吗?我不清楚他所说的“保留”是什么意思,你认为这意味着把它作为字符串保留吗?这对我来说似乎很奇怪。我不知道如何在列表中存储看起来像键值对的东西,除非他想要它们作为元组?这将是相当简单的,但我做了最一般的事情,因为没有澄清。好的。您认为我应该在回答中提供一个替代实现吗?我只是把它作为一个子目录进行解析,并假设“保留”意味着将它作为一个子目录而不是合并到主目录中。我认为假设一本字典是完全合理的:)可能最好在投入更多工作之前等待OP的澄清。我不清楚他所说的“保留”是什么意思你认为那意味着把它当作一根绳子?这对我来说似乎很奇怪。我不知道如何在列表中存储看起来像键值对的东西,除非他想要它们作为元组?这将是相当简单的,但我做了最一般的事情,因为没有澄清。好的。您认为我应该在回答中提供一个替代实现吗?我只是把它作为一个子目录进行解析,并假设“保留”意味着将它作为一个子目录而不是合并到主目录中。我认为假设一个字典是完全合理的:)在投入更多的工作之前,可能最好等待OP的澄清。