有时我会从json api下载数据,然后中途中断,通常是由于网络超时或其他一些问题。但是,在这种情况下,我希望能够读取可用的数据。这是一个例子:
{
"response": 200,
"message": None,
"params": []
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"},
{"id": "Fmfgo9
我希望能够“完成字符串”,以便我能够将不完整的响应解析为 json。例如:
s = '''
{
"response": 200,
"message": null,
"params": [],
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"}
]
}
}'''
json.loads(s)
{'response': 200, 'message': None, 'params': [], 'body': {'timestamp': 1546033192, '_d': [{'id': 'FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz'}, {'id': 'FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH'}]}}
如何使用任意构造的 json 对象(如上面的内容)来执行上述操作?
为此任务编写解析器的想法在智力上确实很有趣,但我强烈警告您不要遵循这种方法。
根本问题是,当网络请求失败时,您将进入未定义行为的领域。您绝对无法保证最终的输出是什么,因此您可能不应该尝试欺骗。
两种可能性是您的输入不完整但部分可理解,或者完全不可理解。增加的复杂性加上失败的网络请求的未定义性质意味着您可能不应该尝试定义它。
以TCP/IP协议如何处理类似问题为例。在网络中,经常会出现“丢包”的情况,这意味着某些数据无法完全传输。引用维基百科的话,TCP“检测数据包丢失并执行重传以确保可靠的消息传递”。 我强烈建议采用类似的方法。要么重新获取数据,要么简单地将错误视为福音并对错误状态执行某些操作。
}
和
]
字符来尝试“完成”。它有点冗长并且可以清理,但它适用于我尝试过的一些字符串输入:s='''{
"response": 200,
"message": null,
"params": [],
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"},
{"id": "Fmfgo9'''
>>> f.complete_json_structure(s)
{'response': 200, 'message': None, 'params': [], 'body': {'timestamp': 1546033192, '_d': [{'id': 'FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz'}, {'id': 'FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH'}]}}
这是代码:
# Build the 'unfinished character' stack
unfinished = []
for char in file_data:
if char in ['{', '[']:
unfinished.append(char)
elif char in ['}', ']']:
inverse_char = '{' if char == '}' else '['
# Remove the last one
unfinished.reverse()
unfinished.remove(inverse_char)
unfinished.reverse()
# Build the 'closing occurrence string'
unfinished.reverse()
unfinished = ['}' if (char == '{') else ']' for char in unfinished]
unfinished_str = ''.join(unfinished)
# Do a while loop to try and parse the json
data = None
while True:
if not json_string:
raise FileParserError("Could not parse the JSON file or infer its format.")
if json_string[-1] in ('}', ']'):
try:
data = json.loads(json_string + unfinished_str)
except json.decoder.JSONDecodeError:
# do it a second time as a sort of hack to fix the "trailing comma issue" (or could do a remove last comma, but that gets tricky)
try:
data = json.loads(json_string + unfinished_str[1:])
except json.decoder.JSONDecodeError:
pass
if data is not None:
break
if json_string[-1] == unfinished_str[0]:
unfinished_str = unfinished_str[1:]
json_string = json_string[:-1].strip().rstrip(',')
return data