将难看的字符串(自定义非 json 格式)转换为字典
Convert ugly string (custom non-json format) to dictionary
我有这个字符串,我想将其作为字典加载,以便我可以访问每一项。
my_str = "[
id=xyz-111,
abc= {
item=[
{
a=xyz,
b=123,
c={},
d={
i=[{ip=0.0.0.0/0}]
},
}
]
}
]"
目前我正在使用正则表达式(re library)来获取字符串中任何项目的值,这很有效。
有没有更简洁的方法将这个字符串转换成字典?我试过 json.loads()
和 ast
都不起作用。
预期结果:
my_dict = {
'id':'xyz-111',
'abc': {
'item':[
{
'a':'xyz',
'b':123,
'c':{},
'd':{
'i':[{'ip':'0.0.0.0/0'}]
},
}
]
}
}
我同意你的看法,通常 json.loads()
将是摄取它的首选。该字符串从何而来?
正确的解决方案
似乎 layer_1 的某些代码生成了格式良好的 JSON,
然后 layer_2 删除引号。
找到 layer_2,并告诉它停止这样做。
或者,复制 layer_2,
让您自己的代码使用原始输入
并更好地处理它,
这样引号就不会丢失。
骇人听闻的解决方案
肯定是一些结构留在那里,
在标点符号和行尾之间,
所以在最坏的情况下,你值得花时间破解一个 UnStrip
放回丢失的引号的例程。
在例如的情况下b=123
, 发射 'b':'123'
也不会太糟糕,
正如您始终可以 post 处理的那样,
您递归地尝试将字典值转换为数字的地方,
如果值结果为 try
/ except
则忽略错误
看起来更像 'xyz'
而不是某个整数。
实际上,将 n = float(s)
包裹在 try
中的示例很有启发性。
输入的任何给定行都可能存在一些歧义,
可选择尝试将变体 A 或 B 视为有效 JSON。
尝试两者可能会有用,包裹在 try
,
return 第一个获胜的人,
第一个评估为有效 JSON.
好吧,这很难看,但它可以为您提供一个创建更有效解决方案的起点。基本上,与第一个替换的一系列替换包括切片和用 dict 闭包替换左括号和右括号。然后,ast.literal_eval
转换为dict。
import ast
import re
s = """
[
id=xyz-111,
abc= {
item=[
{
a=xyz,
b=123,
c={},
d={
i=[{ip=0.0.0.0/0}]
},
}
]
}
]
"""
a = '{' + re.sub(r'=', r':', re.sub(r'\s+', '', s))[1:-1] + '}'
b = re.sub(r'([{}[\]:,])([^{}[\]:,])', r'"', a)
c = re.sub(r'([^{}[\]:,])([{}[\]:,])', r'"', b)
d = ast.literal_eval(c)
print(d)
# {'id': 'xyz-111', 'abc': {'item': [{'a': 'xyz', 'b': '123', 'c': {}, 'd': {'i': [{'ip': '0.0.0.0/0'}]}}]}}
a
删除所有空格,将 =
替换为 :
,并将外部 []
替换为 {}
(删除空格是一种钝器和如果数据包含需要保留空格的字符串,则需要更具体地定位)
b
在括号、分号或逗号之后插入 "
,但后面没有任何这些字符
c
在方括号、分号或逗号之前插入 "
,前面没有这些字符
d
使用 ast.literal_eval
将字符串转换为字典,这比 json.loads
稍微宽容一些
我有这个字符串,我想将其作为字典加载,以便我可以访问每一项。
my_str = "[
id=xyz-111,
abc= {
item=[
{
a=xyz,
b=123,
c={},
d={
i=[{ip=0.0.0.0/0}]
},
}
]
}
]"
目前我正在使用正则表达式(re library)来获取字符串中任何项目的值,这很有效。
有没有更简洁的方法将这个字符串转换成字典?我试过 json.loads()
和 ast
都不起作用。
预期结果:
my_dict = {
'id':'xyz-111',
'abc': {
'item':[
{
'a':'xyz',
'b':123,
'c':{},
'd':{
'i':[{'ip':'0.0.0.0/0'}]
},
}
]
}
}
我同意你的看法,通常 json.loads()
将是摄取它的首选。该字符串从何而来?
正确的解决方案
似乎 layer_1 的某些代码生成了格式良好的 JSON, 然后 layer_2 删除引号。 找到 layer_2,并告诉它停止这样做。 或者,复制 layer_2, 让您自己的代码使用原始输入 并更好地处理它, 这样引号就不会丢失。
骇人听闻的解决方案
肯定是一些结构留在那里,
在标点符号和行尾之间,
所以在最坏的情况下,你值得花时间破解一个 UnStrip
放回丢失的引号的例程。
在例如的情况下b=123
, 发射 'b':'123'
也不会太糟糕,
正如您始终可以 post 处理的那样,
您递归地尝试将字典值转换为数字的地方,
如果值结果为 try
/ except
则忽略错误
看起来更像 'xyz'
而不是某个整数。
实际上,将 n = float(s)
包裹在 try
中的示例很有启发性。
输入的任何给定行都可能存在一些歧义,
可选择尝试将变体 A 或 B 视为有效 JSON。
尝试两者可能会有用,包裹在 try
,
return 第一个获胜的人,
第一个评估为有效 JSON.
好吧,这很难看,但它可以为您提供一个创建更有效解决方案的起点。基本上,与第一个替换的一系列替换包括切片和用 dict 闭包替换左括号和右括号。然后,ast.literal_eval
转换为dict。
import ast
import re
s = """
[
id=xyz-111,
abc= {
item=[
{
a=xyz,
b=123,
c={},
d={
i=[{ip=0.0.0.0/0}]
},
}
]
}
]
"""
a = '{' + re.sub(r'=', r':', re.sub(r'\s+', '', s))[1:-1] + '}'
b = re.sub(r'([{}[\]:,])([^{}[\]:,])', r'"', a)
c = re.sub(r'([^{}[\]:,])([{}[\]:,])', r'"', b)
d = ast.literal_eval(c)
print(d)
# {'id': 'xyz-111', 'abc': {'item': [{'a': 'xyz', 'b': '123', 'c': {}, 'd': {'i': [{'ip': '0.0.0.0/0'}]}}]}}
a
删除所有空格,将=
替换为:
,并将外部[]
替换为{}
(删除空格是一种钝器和如果数据包含需要保留空格的字符串,则需要更具体地定位)b
在括号、分号或逗号之后插入"
,但后面没有任何这些字符c
在方括号、分号或逗号之前插入"
,前面没有这些字符d
使用ast.literal_eval
将字符串转换为字典,这比json.loads
稍微宽容一些