비활성 JSON 문자열을 자동으로 수정하려면 어떻게 해야 합니까?
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)
expecting , delimiter : 행1 컬럼3646 (char 3645)
제목: "센터 "어드밴스"에 인용된 문제인 것 같습니다.
Python에서 자동 수정하려면 어떻게 해야 하나요?
@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
모듈, OS, 또는 로케일의 어느 쪽인가에 따라서 이 솔루션을 조정할 필요가 있는 경우가 있습니다.
이것이 정확히 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\"",
위의 아이디어도 좋지만 나는 그것에 문제가 있었다.내 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)
유일한 현실적이고 확실한 해결책은 API를 수정하도록 2gs에 요청하는 것입니다.
그 사이에, 문자열내의 이중 따옴표가 없는 부정한 부호화 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
}
}
]
}
니즈가 완전히 충족되지 않으면 기능을 쉽게 커스터마이즈할 수 있습니다.
JSON 문자열에서는 다음과 같이 큰따옴표를 이스케이프해야 합니다.
"title": "Образовательный центр \"ADVANCE\"",
프로그래밍 방식으로 수정하려면 JSON 파서를 수정하여 오류에 대한 컨텍스트를 확보한 후 복구를 시도하는 것이 가장 간단한 방법입니다.
저는 이런 문제를 해결하기 위해 jsonfixer를 만듭니다.
Python Package (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)
https://fix-json.com의 소스 내에서 해결책을 찾았지만, 매우 더럽고 해킹처럼 보입니다.비단뱀에 적응하기만 하면 된다.
jsString.match(/:.*"(.*)"/gi).forEach(function(element){
var filtered = element.replace(/(^:\s*"|"(,)?$)/gi, '').trim();
jsString = jsString.replace(filtered, filtered.replace(/(\\*)\"/gi, "\\\""));
});
완벽하지도 않고 못생기지도 않지만 나에게 도움이 된다.
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
수정 #1
일부 웹 사이트에서 가져온 경우 동일한 문자열을 사용하고 있는지 확인하십시오..replace('\\"','"')
이 때문에 데이터는 더 이상 json이 아니었다..렇게게고고고고고
수정 #2
키 이름의 모든 위치에 문자를 추가해 보십시오.화창하대요.
언급URL : https://stackoverflow.com/questions/18514910/how-do-i-automatically-fix-an-invalid-json-string
'source' 카테고리의 다른 글
HTML5 비디오에서 오른쪽 클릭을 비활성화하시겠습니까? (0) | 2023.03.05 |
---|---|
디렉티브의 method 인수가 AngularJS에 지정되어 있는지 확인하는 방법 (0) | 2023.03.05 |
상위 구성 요소의 하위 구성 요소 참조에 액세스하는 방법 (0) | 2023.03.05 |
jQuery의 .ajax() 메서드가 세션쿠키를 송신하지 않는 이유는 무엇입니까? (0) | 2023.03.05 |
Chai: '해야' 구문을 사용하여 정의되지 않았는지 테스트하는 방법 (0) | 2023.03.05 |