Python json 解析器允许重复键
Python json parser allow duplicate keys
我需要解析一个 json 文件,不幸的是,它不符合原型。我有两个数据问题,但我已经找到了解决方法,所以我会在最后提到它,也许有人也可以提供帮助。
所以我需要像这样解析条目:
"Test":{
"entry":{
"Type":"Something"
},
"entry":{
"Type":"Something_Else"
}
}, ...
json 默认解析器更新字典,因此仅使用最后一个条目。我还必须以某种方式存储另一个,但我不知道该怎么做。我还必须按照它们在文件中出现的相同顺序将键存储在几个字典中,这就是为什么我使用 OrderedDict 来这样做。它工作正常,所以如果有任何方法可以用重复的条目扩展它,我将不胜感激。
我的第二个问题是这个 json 文件包含这样的条目:
"Test":{
{
"Type":"Something"
}
}
Json.load() 函数在到达 json 文件中的该行时引发异常。我解决这个问题的唯一方法是自己手动移除内括号。
提前致谢
您可以使用 JSONDecoder.object_pairs_hook
自定义 JSONDecoder
解码对象的方式。这个钩子函数将传递一个 (key, value)
对的列表,你通常会对其进行一些处理,然后变成 dict
.
但是,由于 Python 字典不允许重复的键(而且您根本无法更改它),您可以 return 挂钩中未更改的对并获得嵌套列表(key, value)
对当你解码你的 JSON:
from json import JSONDecoder
def parse_object_pairs(pairs):
return pairs
data = """
{"foo": {"baz": 42}, "foo": 7}
"""
decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj
输出:
[(u'foo', [(u'baz', 42)]), (u'foo', 7)]
如何使用这个数据结构由你决定。如上所述,Python 字典不允许重复键,而且没有办法解决这个问题。您甚至如何根据键进行查找? dct[key]
会有歧义。
因此,您可以实施自己的逻辑来按照您期望的方式处理查找,或者实施某种避免冲突的方法来使键唯一(如果它们不是),然后然后 从嵌套列表创建字典。
编辑:既然你说你想修改重复键以使其唯一,那么你可以这样做:
from collections import OrderedDict
from json import JSONDecoder
def make_unique(key, dct):
counter = 0
unique_key = key
while unique_key in dct:
counter += 1
unique_key = '{}_{}'.format(key, counter)
return unique_key
def parse_object_pairs(pairs):
dct = OrderedDict()
for key, value in pairs:
if key in dct:
key = make_unique(key, dct)
dct[key] = value
return dct
data = """
{"foo": {"baz": 42, "baz": 77}, "foo": 7, "foo": 23}
"""
decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj
输出:
OrderedDict([(u'foo', OrderedDict([(u'baz', 42), ('baz_1', 77)])), ('foo_1', 7), ('foo_2', 23)])
make_unique
函数负责return 生成无冲突密钥。在此示例中,它只是在密钥后缀 _n
,其中 n
是增量计数器 - 只需根据您的需要进行调整即可。
因为 object_pairs_hook
完全按照它们在 JSON 文档中出现的顺序接收对,所以也可以通过使用 OrderedDict
来保留该顺序,我将其包括为嗯。
非常感谢@Lukas Graf,我通过实现我自己的钩子函数版本使它也能正常工作
def dict_raise_on_duplicates(ordered_pairs):
count=0
d=collections.OrderedDict()
for k,v in ordered_pairs:
if k in d:
d[k+'_dupl_'+str(count)]=v
count+=1
else:
d[k]=v
return d
唯一剩下的就是自动去掉双括号,我完成了:D 再次感谢
如果您希望将那些重复的键转换成一个数组,而不是单独的副本,这可以完成工作:
def dict_raise_on_duplicates(ordered_pairs):
"""Convert duplicate keys to JSON array."""
d = {}
for k, v in ordered_pairs:
if k in d:
if type(d[k]) is list:
d[k].append(v)
else:
d[k] = [d[k],v]
else:
d[k] = v
return d
然后你只需使用:
dict = json.loads(yourString, object_pairs_hook=dict_raise_on_duplicates)
我需要解析一个 json 文件,不幸的是,它不符合原型。我有两个数据问题,但我已经找到了解决方法,所以我会在最后提到它,也许有人也可以提供帮助。
所以我需要像这样解析条目:
"Test":{
"entry":{
"Type":"Something"
},
"entry":{
"Type":"Something_Else"
}
}, ...
json 默认解析器更新字典,因此仅使用最后一个条目。我还必须以某种方式存储另一个,但我不知道该怎么做。我还必须按照它们在文件中出现的相同顺序将键存储在几个字典中,这就是为什么我使用 OrderedDict 来这样做。它工作正常,所以如果有任何方法可以用重复的条目扩展它,我将不胜感激。
我的第二个问题是这个 json 文件包含这样的条目:
"Test":{
{
"Type":"Something"
}
}
Json.load() 函数在到达 json 文件中的该行时引发异常。我解决这个问题的唯一方法是自己手动移除内括号。
提前致谢
您可以使用 JSONDecoder.object_pairs_hook
自定义 JSONDecoder
解码对象的方式。这个钩子函数将传递一个 (key, value)
对的列表,你通常会对其进行一些处理,然后变成 dict
.
但是,由于 Python 字典不允许重复的键(而且您根本无法更改它),您可以 return 挂钩中未更改的对并获得嵌套列表(key, value)
对当你解码你的 JSON:
from json import JSONDecoder
def parse_object_pairs(pairs):
return pairs
data = """
{"foo": {"baz": 42}, "foo": 7}
"""
decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj
输出:
[(u'foo', [(u'baz', 42)]), (u'foo', 7)]
如何使用这个数据结构由你决定。如上所述,Python 字典不允许重复键,而且没有办法解决这个问题。您甚至如何根据键进行查找? dct[key]
会有歧义。
因此,您可以实施自己的逻辑来按照您期望的方式处理查找,或者实施某种避免冲突的方法来使键唯一(如果它们不是),然后然后 从嵌套列表创建字典。
编辑:既然你说你想修改重复键以使其唯一,那么你可以这样做:
from collections import OrderedDict
from json import JSONDecoder
def make_unique(key, dct):
counter = 0
unique_key = key
while unique_key in dct:
counter += 1
unique_key = '{}_{}'.format(key, counter)
return unique_key
def parse_object_pairs(pairs):
dct = OrderedDict()
for key, value in pairs:
if key in dct:
key = make_unique(key, dct)
dct[key] = value
return dct
data = """
{"foo": {"baz": 42, "baz": 77}, "foo": 7, "foo": 23}
"""
decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj
输出:
OrderedDict([(u'foo', OrderedDict([(u'baz', 42), ('baz_1', 77)])), ('foo_1', 7), ('foo_2', 23)])
make_unique
函数负责return 生成无冲突密钥。在此示例中,它只是在密钥后缀 _n
,其中 n
是增量计数器 - 只需根据您的需要进行调整即可。
因为 object_pairs_hook
完全按照它们在 JSON 文档中出现的顺序接收对,所以也可以通过使用 OrderedDict
来保留该顺序,我将其包括为嗯。
非常感谢@Lukas Graf,我通过实现我自己的钩子函数版本使它也能正常工作
def dict_raise_on_duplicates(ordered_pairs):
count=0
d=collections.OrderedDict()
for k,v in ordered_pairs:
if k in d:
d[k+'_dupl_'+str(count)]=v
count+=1
else:
d[k]=v
return d
唯一剩下的就是自动去掉双括号,我完成了:D 再次感谢
如果您希望将那些重复的键转换成一个数组,而不是单独的副本,这可以完成工作:
def dict_raise_on_duplicates(ordered_pairs):
"""Convert duplicate keys to JSON array."""
d = {}
for k, v in ordered_pairs:
if k in d:
if type(d[k]) is list:
d[k].append(v)
else:
d[k] = [d[k],v]
else:
d[k] = v
return d
然后你只需使用:
dict = json.loads(yourString, object_pairs_hook=dict_raise_on_duplicates)