source

비활성 JSON 문자열을 자동으로 수정하려면 어떻게 해야 합니까?

nicesource 2023. 3. 5. 09:55
반응형

비활성 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

반응형