从2gis API我得到了以下JSON字符串。
{
"api_version": "1.3",
"response_code": "200",
"id": "3237490513229753",
"lon": "38.969916127827",
"lat": "45.069889625267",
"page_url": null,
"name": "ATB",
"firm_group": {
"id": "3237499103085728",
"count": "1"
},
"city_name": "Krasnodar",
"city_id": "3237585002430511",
"address": "Turgeneva, 172/1",
"create_time": "2008-07-22 10:02:04 07",
"modification_time": "2013-08-09 20:04:36 07",
"see_also": [
{
"id": "3237491513434577",
"lon": 38.973110606808,
"lat": 45.029031222211,
"name": "Advance",
"hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e",
"ads": {
"sponsored_article": {
"title": "Center "ADVANCE"",
"text": "Business.English."
},
"warning": null
}
}
]
}
但是Python并没有认识到它:
json.loads(firm_str)
期待,分隔符:第1行第3646行(字符3645)
看起来像引号中的问题: " title":" Center" ADVANCE""
如何在Python中自动修复它?
答案 0 :(得分:28)
answer by @Michael给了我一个想法...不是一个非常漂亮的想法,但它似乎工作,至少在你的例子上:尝试解析JSON字符串,如果它失败,寻找字符它在异常字符串 1 中失败并替换该字符。
while True:
try:
result = json.loads(s) # try to parse...
break # parsing worked -> exit loop
except Exception as e:
# "Expecting , delimiter: line 34 column 54 (char 1158)"
# position of unexpected character after '"'
unexp = int(re.findall(r'\(char (\d+)\)', str(e))[0])
# position of unescaped '"' before that
unesc = s.rfind(r'"', 0, unexp)
s = s[:unesc] + r'\"' + s[unesc+1:]
# position of correspondig closing '"' (+2 for inserted '\')
closg = s.find(r'"', unesc + 2)
s = s[:closg] + r'\"' + s[closg+1:]
print result
您可能需要添加一些额外的检查以防止它以无限循环结束(例如,最大重复次数与字符串中的字符一样多)。 此外,如果不正确的 "
后面跟一个逗号,这仍然无效,正如@gnibbler所指出的那样。
更新:这似乎很好地漂亮现在(尽管仍然不完美),即使未转义的"
后跟逗号或关闭括号,因为在这种情况下,它可能会在此之后(预期的属性名称等)得到关于语法错误的抱怨并追溯到最后的"
。它还会自动转义相应的结束"
(假设有一个)。
1)例外的str
是"Expecting , delimiter: line XXX column YYY (char ZZZ)"
,其中ZZZ是发生错误的字符串中的位置。但请注意,此消息可能取决于Python的版本,json
模块,操作系统或区域设置,因此可能必须相应地调整此解决方案。
答案 1 :(得分:7)
如果这正是API返回的原因,则其API存在问题。这是无效的JSON。特别是在这个地区:
"ads": {
"sponsored_article": {
"title": "Образовательный центр "ADVANCE"", <-- here
"text": "Бизнес.Риторика.Английский язык.Подготовка к школе.Подготовка к ЕГЭ."
},
"warning": null
}
ADVANCE周围的双引号未被转义。您可以使用http://jsonlint.com/之类的内容来验证它。
这是"
没有被转义的问题,如果这是你得到的,那么数据来源不好。他们需要解决它。
Parse error on line 4:
...азовательный центр "ADVANCE"",
-----------------------^
Expecting '}', ':', ',', ']'
这解决了问题:
"title": "Образовательный центр \"ADVANCE\"",
答案 2 :(得分:4)
唯一真实且明确的解决方案是让2gis修复他们的API。
与此同时,可以在字符串中修复编码错误的JSON转义双引号。如果每个键值对后跟一个换行符(因为它似乎来自发布的数据),以下函数将完成这项工作:
def fixjson(badjson):
s = badjson
idx = 0
while True:
try:
start = s.index( '": "', idx) + 4
end1 = s.index( '",\n',idx)
end2 = s.index( '"\n', idx)
if end1 < end2:
end = end1
else:
end = end2
content = s[start:end]
content = content.replace('"', '\\"')
s = s[:start] + content + s[end:]
idx = start + len(content) + 6
except:
return s
请注意,做了一些补充:
该函数试图转义属于键值对的值字符串中的双引号字符。
假设要转义的文本在序列
之后开始": "
并在序列之前结束
",\n
或
"\n
将发布的JSON传递给函数会产生此返回值
{
"api_version": "1.3",
"response_code": "200",
"id": "3237490513229753",
"lon": "38.969916127827",
"lat": "45.069889625267",
"page_url": null,
"name": "ATB",
"firm_group": {
"id": "3237499103085728",
"count": "1"
},
"city_name": "Krasnodar",
"city_id": "3237585002430511",
"address": "Turgeneva, 172/1",
"create_time": "2008-07-22 10:02:04 07",
"modification_time": "2013-08-09 20:04:36 07",
"see_also": [
{
"id": "3237491513434577",
"lon": 38.973110606808,
"lat": 45.029031222211,
"name": "Advance",
"hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e",
"ads": {
"sponsored_article": {
"title": "Center \"ADVANCE\"",
"text": "Business.English."
},
"warning": null
}
}
]
}
请记住,如果您的需求不能完全满足,您可以轻松自定义功能。
答案 3 :(得分:2)
您需要在JSON字符串中转义双引号,如下所示:
"title": "Образовательный центр \\"ADVANCE\\"",
要以编程方式修复它,最简单的方法是修改JSON解析器,以便为错误提供一些上下文,然后尝试修复它。
答案 4 :(得分:1)
上述想法很好,但我遇到了问题。我的json Sting只包含一个额外的双引号。 所以,我修复了上面给出的代码。
jsonStr是
{
"api_version": "1.3",
"response_code": "200",
"id": "3237490513229753",
"lon": "38.969916127827",
"lat": "45.069889625267",
"page_url": null,
"name": "ATB",
"firm_group": {
"id": "3237499103085728",
"count": "1"
},
"city_name": "Krasnodar",
"city_id": "3237585002430511",
"address": "Turgeneva, 172/1",
"create_time": "2008-07-22 10:02:04 07",
"modification_time": "2013-08-09 20:04:36 07",
"see_also": [
{
"id": "3237491513434577",
"lon": 38.973110606808,
"lat": 45.029031222211,
"name": "Advance",
"hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e",
"ads": {
"sponsored_article": {
"title": "Center "ADVANCE",
"text": "Business.English."
},
"warning": null
}
}
]
}
修复方法如下:
import json, re
def fixJSON(jsonStr):
# Substitue all the backslash from JSON string.
jsonStr = re.sub(r'\\', '', jsonStr)
try:
return json.loads(jsonStr)
except ValueError:
while True:
# Search json string specifically for '"'
b = re.search(r'[\w|"]\s?(")\s?[\w|"]', jsonStr)
# If we don't find any the we come out of loop
if not b:
break
# Get the location of \"
s, e = b.span(1)
c = jsonStr[s:e]
# Replace \" with \'
c = c.replace('"',"'")
jsonStr = jsonStr[:s] + c + jsonStr[e:]
return json.loads(jsonStr)
此代码也适用于问题陈述
中提到的JSON字符串或者您也可以这样做:
def fixJSON(jsonStr):
# First remove the " from where it is supposed to be.
jsonStr = re.sub(r'\\', '', jsonStr)
jsonStr = re.sub(r'{"', '{`', jsonStr)
jsonStr = re.sub(r'"}', '`}', jsonStr)
jsonStr = re.sub(r'":"', '`:`', jsonStr)
jsonStr = re.sub(r'":', '`:', jsonStr)
jsonStr = re.sub(r'","', '`,`', jsonStr)
jsonStr = re.sub(r'",', '`,', jsonStr)
jsonStr = re.sub(r',"', ',`', jsonStr)
jsonStr = re.sub(r'\["', '\[`', jsonStr)
jsonStr = re.sub(r'"\]', '`\]', jsonStr)
# Remove all the unwanted " and replace with ' '
jsonStr = re.sub(r'"',' ', jsonStr)
# Put back all the " where it supposed to be.
jsonStr = re.sub(r'\`','\"', jsonStr)
return json.loads(jsonStr)
答案 5 :(得分:1)
我制作了一个jsonfixer来解决这样的问题。
这是Python软件包(2.7)(半完成的命令行工具)
只要看看https://github.com/half-pie/half-json
from half_json.core import JSONFixer
f = JSONFixer(max_try=100)
new_s = s.replace('\n', '')
result = f.fix(new_s)
d = json.loads(result.line)
# {u'name': u'ATB', u'modification_time': u'2013-08-09 20:04:36 07', u'city_id': u'3237585002430511', u'see_also': [{u'hash': u'5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e', u'ads': {u'warning': None, u'sponsored_article': {u'ADVANCE': u', ', u'text': u'Business.English.', u'title': u'Center '}}, u'lon': 38.973110606808, u'lat': 45.029031222211, u'id': u'3237491513434577', u'name': u'Advance'}], u'response_code': u'200', u'lon': u'38.969916127827', u'firm_group': {u'count': u'1', u'id': u'3237499103085728'}, u'create_time': u'2008-07-22 10:02:04 07', u'city_name': u'Krasnodar', u'address': u'Turgeneva, 172/1', u'lat': u'45.069889625267', u'id': u'3237490513229753', u'api_version': u'1.3', u'page_url': None}
和https://github.com/half-pie/half-json/blob/master/tests/test_cases.py#L76-L80中的测试用例
line = '{"title": "Center "ADVANCE"", "text": "Business.English."}'
ok, newline, _ = JSONFixer().fix(line)
self.assertTrue(ok)
self.assertEqual('{"title": "Center ","ADVANCE":", ","text": "Business.English."}', newline)
答案 6 :(得分:0)
在https://fix-json.com的来源中,我找到了一个解决方案,但是它很脏,看起来像是黑客。只需将其适应python
jsString.match(/:.*"(.*)"/gi).forEach(function(element){
var filtered = element.replace(/(^:\s*"|"(,)?$)/gi, '').trim();
jsString = jsString.replace(filtered, filtered.replace(/(\\*)\"/gi, "\\\""));
});
答案 7 :(得分:0)
这并不完美又丑陋,但对我有帮助
def get_json_info(info_row: str, type) -> dict:
try:
info = json.loads(info_row)
except JSONDecodeError:
data = {
}
try:
for s in info_row.split('","'):
if not s:
continue
key, val = s.split(":", maxsplit=1)
key = key.strip().lstrip("{").strip('"')
val: str = re.sub('"', '\\"', val.lstrip('"').strip('\"}'))
data[key] = val
except ValueError:
print("ERROR:", info_row)
info = data
return info
答案 8 :(得分:0)
修复#1
如果您是从某些网站获取的,请确保您使用的字符串相同。就我而言,我正在做.replace('\\"','"')
。因此,数据不再是json。如果您也做了什么。那样,请解决该问题。
修复#2
尝试在密钥名称的所有位置添加一些字符。会没事的。