2013-08-29 38 views
12

Từ API 2gis, tôi nhận được chuỗi JSON sau.Làm cách nào để tự động sửa một chuỗi JSON không hợp lệ?

{ 
    "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 
      } 
     } 
    ] 
} 

Nhưng Python không nhận ra nó:

json.loads(firm_str) 

Expecting, delimiter: dòng 1 cột 3646 (char 3645)

Nó trông giống như một vấn đề với dấu ngoặc kép trong : "tiêu đề": "Trung tâm" ADVANCE ""

Làm cách nào để khắc phục sự cố tự động ically bằng Python?

+4

Đây là sự cố mã hóa, không phải vấn đề JSON. Mã hóa – Gijs

+0

là đúng. không chú ý đến các ký tự lạ –

+0

Bạn có thể cô lập điều này thành một ví dụ nhỏ cụ thể không? Hủy bỏ phần cho đến khi bạn còn lại với bit mà phá vỡ. – Joe

Trả lời

20

Câu trả lời của @Michael đã cho tôi một ý tưởng ... không phải là một ý tưởng rất hay, nhưng dường như nó hoạt động, ít nhất là ví dụ của bạn: Hãy thử phân tích cú pháp chuỗi JSON, và nếu nó không thành công, hãy tìm ký tự nơi nó không thành công trong chuỗi ngoại lệ và thay thế ký tự đó.

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 

Bạn có thể muốn thêm một số kiểm tra bổ sung để ngăn điều này kết thúc bằng vòng lặp vô hạn (ví dụ: tối đa nhiều lần lặp lại có các ký tự trong chuỗi). Ngoài ra, điều này sẽ vẫn không hoạt động nếu không đúng " thực sự được theo sau bởi dấu phẩy, như được chỉ ra bởi @gnibbler.

Cập nhật: Điều này dường như làm việc khá tốt bây giờ (mặc dù vẫn chưa hoàn hảo), ngay cả khi unescaped " Tiếp theo là một dấu phẩy, hoặc đóng khung, như trong trường hợp này nó có khả năng sẽ nhận được một khiếu nại về lỗi cú pháp sau đó (tên thuộc tính dự kiến, v.v.) và theo dõi trở lại " cuối cùng. Nó cũng tự động thoát khỏi việc đóng tương ứng " (giả sử có một).

+0

Tuyệt vời. Điều này không khắc phục được tất cả các vấn đề của tôi, nhưng đó là một khởi đầu tốt. – eandersson

+0

@eandersson Bạn có thể cụ thể hơn về những gì bạn mong đợi là "giải pháp hoàn chỉnh hơn" trông giống như thế nào? Các trường hợp giải pháp của tôi không hoạt động là gì? Tôi chắc chắn có nhiều, nhưng cái nào phù hợp với bạn?) –

+0

Tôi chủ yếu đề cập đến một thư viện để xử lý các loại kỳ quặc này, nhưng cũng là giải pháp linh hoạt hơn để khắc phục các sự cố nghiêm trọng mà điều này không thể xử lý được. Một ví dụ sẽ là một chuỗi với một dấu nháy kép đơn. – eandersson

6

Nếu đây chính xác là những gì API đang trả lại thì có vấn đề với API của họ. Đây là JSON không hợp lệ. Đặc biệt xung quanh khu vực này:

"ads": { 
      "sponsored_article": { 
       "title": "Образовательный центр "ADVANCE"", <-- here 
       "text": "Бизнес.Риторика.Английский язык.Подготовка к школе.Подготовка к ЕГЭ." 
      }, 
      "warning": null 
     } 

Dấu ngoặc kép xung quanh ADVANCE không được thoát. Bạn có thể biết bằng cách sử dụng một cái gì đó như http://jsonlint.com/ để xác thực nó.

Đây là vấn đề với " không bị thoát, dữ liệu có hại ở nguồn nếu đây là những gì bạn đang nhận được. Họ cần phải sửa chữa nó.

Parse error on line 4: 
...азовательный центр "ADVANCE"",   
-----------------------^ 
Expecting '}', ':', ',', ']' 

này sửa chữa các vấn đề:

"title": "Образовательный центр \"ADVANCE\"", 
+0

Tôi cần sửa lỗi này tự động. –

+6

Bạn nên bắt đầu bằng cách viết thư cho '2gis' và nói với họ rằng họ không trả về đúng JSON. – Joe

+0

Bạn có thể thử bằng cách phân tích cú pháp JSON và, nếu nó không thành công, 'jsonString.replace ('" "', '\" "')'. Điều đó có thể hiệu quả. Nhưng nó có thể thất bại trên các đầu vào khác. Không có giải pháp đúng. – Joe

2

Bạn cần phải thoát khỏi dấu ngoặc kép trong chuỗi JSON, như sau:

"title": "Образовательный центр \\"ADVANCE\\"", 

Để khắc phục nó lập trình, cách đơn giản nhất sẽ được sửa đổi trình phân tích cú pháp JSON của bạn để bạn có một số ngữ cảnh cho lỗi, sau đó cố sửa chữa nó.

3

Giải pháp thực sự và dứt khoát duy nhất là 2gis để sửa lỗi API của họ.

Trong thời gian chờ đợi, bạn có thể khắc phục được các dấu ngoặc kép được mã hóa JSON trong các chuỗi. Nếu mỗi cặp khóa-giá trị được theo sau bởi một dòng mới (vì nó có vẻ là từ các dữ liệu đăng) các chức năng sau đây sẽ thực hiện công việc:

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 

Xin vui lòng, lưu ý rằng một số assumtions thực hiện:

Các hàm attemps để thoát khỏi các dấu ngoặc kép trong các chuỗi giá trị giá trị thuộc về các cặp khóa-giá trị.

Người ta cho rằng các văn bản để được thoát bắt đầu sau khi chuỗi

": " 

và kết thúc trước khi chuỗi

",\n 

hoặc

"\n 

Đi qua JSON được đưa lên kết quả chức năng trong giá trị trả lại này

{ 
    "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 
      } 
     } 
    ] 
} 

Hãy nhớ rằng bạn có thể dễ dàng tùy chỉnh chức năng nếu nhu cầu của bạn không hoàn toàn hài lòng.

1

Ý tưởng trên là tốt nhưng tôi gặp sự cố với điều đó. Json của tôi Sting chỉ bao gồm một dấu ngoặc kép bổ sung trong đó. Vì vậy, tôi đã sửa chữa mã đã nêu ở trên.

Các jsonStr là

{ 
    "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 
      } 
     } 
    ] 
} 

Việc sửa chữa được như sau:

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) 

Mã này cũng làm việc cho JSON chuỗi đề cập trong báo cáo vấn đề


HOẶC bạn cũng có thể làm này:

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) 
+0

Đẹp, nhưng thay vì xóa tất cả '' 'khỏi văn bản, tại sao không thay thế chúng bằng một số ký tự giữ chỗ (không tìm thấy trong chuỗi) và sau đó thay thế chúng trở lại trích dẫn sau khi '' 'thích hợp đã được đưa trở lại? –

+0

Nó sẽ là một cách thích hợp để làm điều đó. – theBuzzyCoder