Dấu ngoặc kép đơn và dấu ngoặc kép trong JSON


107

Mã của tôi:

import simplejson as json

s = "{'username':'dfdsfdsf'}" #1
#s = '{"username":"dfdsfdsf"}' #2
j = json.loads(s)

#1 định nghĩa là sai

#2 định nghĩa là đúng

Tôi nghe nói rằng trong Python rằng dấu ngoặc képđơn có thể hoán đổi cho nhau. bất cứ ai có thể giải thích điều này với tôi?

Câu trả lời:


169

Cú pháp JSON không phải là cú pháp Python. JSON yêu cầu dấu ngoặc kép cho các chuỗi của nó.


2
nhưng đầu tiên đó là trích dẫn duy nhất trong JSON, tôi bối rối. Cái đó có thể vượt qua biên dịch nhưng cái thứ hai thì không.
Bin Chen

6
Cảm ơn bạn đã xác nhận điều này. Rõ ràng tôi là người duy nhất nhập khẩu str(dict)và không muốn evalđiều đó. Một đơn giản .replace("'", '"')nên làm các thủ thuật.
isaaclw 13/12/12

8
Và tôi đã nói quá sớm. Rõ ràng nó phức tạp hơn thế.
isaaclw 13/12/12

6
Nếu bạn cần phải sử dụng dấu ngoặc kép tất cả xung quanh, bạn có thể gọi json.dumps(..)hai lần như trong: import json; d = dict(tags=["dog", "cat", "mouse"]); print json.dumps(json.dumps(d))mang đến cho:"{\"tags\": [\"dog\", \"cat\", \"mouse\"]}"
rprasad

124

bạn có thể dùng ast.literal_eval()

>>> import ast
>>> s = "{'username':'dfdsfdsf'}"
>>> ast.literal_eval(s)
{'username': 'dfdsfdsf'}

9
Tôi thích câu trả lời này nhất. Json.loads cần một đối số bổ sung hoặc bạn nên sử dụng điều này. Trên toàn cầu thay thế "'" là một thảm họa, như những gì nếu dữ liệu đến là:{ 'a' : 'this "string" really isn\'t!!!!' }
Đánh dấu Gerolimatos

@Mark, phương pháp này có thể được điều chỉnh cho một tình huống phức tạp hơn với các dấu ngoặc kép lồng nhau "{'link':'<a href="mylink">http://my.com</a>'}"không? Trong trường hợp này, ast.literal_evalném lỗi cú pháp
alancalvitti

1
Đây dường như là một rủi ro bảo mật đối với tôi.
JacksonHaenchen

2
Làm thế nào để trả lời câu hỏi này? Điều này có liên quan gì đến dấu ngoặc kép đơn so với dấu ngoặc kép trong JSON? Cách tiếp cận ast này có thể cho phép bạn tải một lệnh Python từ một chuỗi, nhưng vấn đề chính mà OP gặp phải là chuỗi số 1 không phải là JSON hợp lệ trong khi chuỗi số 2 là.
jschultz410

43

Bạn có thể kết xuất JSON với dấu ngoặc kép bằng cách:

import json

# mixing single and double quotes
data = {'jsonKey': 'jsonValue',"title": "hello world"}

# get string with all double quotes
json_string = json.dumps(data) 

12
điều này đi sai đường. bạn đang tuần tự hóa cấu trúc dữ liệu python thành JSON; câu hỏi ban đầu là về giải mã JSON thành cấu trúc dữ liệu python.
tedder42

5
Ý tưởng sẽ là tuần tự hóa python thành json với json.dumps, sau đó gọi json.loads trên đó khi nó ở dạng str.
jheld

3
Bạn bỏ lỡ hiểu ở đây. Nếu bạn muốn tải chuỗi json, nó phải là dấu ngoặc kép. Những gì bạn đang làm vẫn là kết xuất json, không phải chuỗi json.
LegitMe

12

demjson cũng là một gói tốt để giải quyết vấn đề cú pháp json không hợp lệ:

pip install demjson

Sử dụng:

from demjson import decode
bad_json = "{'username':'dfdsfdsf'}"
python_dict = decode(bad_json)

Biên tập:

demjson.decodelà một công cụ tuyệt vời cho json bị hỏng, nhưng khi bạn xử lý lượng lớn dữ liệu json ast.literal_evalthì sẽ phù hợp hơn và nhanh hơn nhiều.


4
demjson.decodelà một công cụ tuyệt vời cho json bị hỏng - nhưng đối với các tác vụ liên quan đến hàng chục hoặc hàng trăm nghìn gói json, ast.literal_evalthì nhanh hơn nhiều. Không demjsoncó nghĩa là không có vị trí của nó: Tôi sử dụng nó như là dự phòng trong trường hợp các phương pháp nhanh hơn không thành công.
mjwunderlich

1
Trên thực tế, demjson hoạt động tốt hơn nhiều, thay vì thử nghiệm với ast.literal_eval và json.loads
Marware

4

Hai vấn đề với câu trả lời được đưa ra cho đến nay, ví dụ: nếu một vấn đề phát trực tuyến JSON không chuẩn như vậy. Bởi vì sau đó người ta có thể phải diễn giải một chuỗi đến (không phải từ điển python).

Vấn đề 1 - demjson: Với Python 3.7. + Và sử dụng conda, tôi không thể cài đặt demjson vì hiện tại nó không hỗ trợ Python> 3.5. Vì vậy, tôi cần một giải pháp với các phương tiện đơn giản hơn, chẳng hạn như astvà / hoặc json.dumps.

Vấn đề 2 - ast& json.dumps: Nếu một JSON vừa được trích dẫn đơn lẻ vừa chứa một chuỗi chứa ít nhất một giá trị, đến lượt nó lại chứa các dấu ngoặc kép, thì giải pháp đơn giản nhưng thực tế duy nhất mà tôi đã tìm thấy là áp dụng cả hai:

Trong ví dụ sau, chúng tôi giả sử linelà đối tượng chuỗi JSON đến:

>>> line = str({'abc':'008565','name':'xyz','description':'can control TV\'s and more'})

Bước 1: chuyển đổi chuỗi đến thành từ điển bằng cách sử dụng ast.literal_eval()
Bước 2: áp dụng json.dumpscho nó để chuyển đổi đáng tin cậy các khóa và giá trị, nhưng không chạm vào nội dung của các giá trị :

>>> import ast
>>> import json
>>> print(json.dumps(ast.literal_eval(line)))
{"abc": "008565", "name": "xyz", "description": "can control TV's and more"}

json.dumpsmột mình sẽ không thực hiện công việc vì nó không diễn giải JSON, mà chỉ thấy chuỗi. Tương tự cho ast.literal_eval(): mặc dù nó diễn giải chính xác JSON (từ điển), nhưng nó không chuyển đổi những gì chúng ta cần.


3

Bạn có thể sửa nó theo cách đó:

s = "{'username':'dfdsfdsf'}"
j = eval(s)

sử dụng ast.literal_eval thay vì eval để giúp tránh các cuộc tấn công tiêm
Simon Kingaby

2

Như đã nói, JSON không phải là cú pháp Python. Bạn cần sử dụng dấu ngoặc kép trong JSON. Người tạo ra nó (trong-) nổi tiếng vì sử dụng các tập con nghiêm ngặt của cú pháp cho phép để giảm bớt tình trạng quá tải nhận thức của lập trình viên.


Dưới đây có thể không thành công nếu một trong các chuỗi JSON chứa một trích dẫn duy nhất như được chỉ ra bởi @Jiaaro. KHÔNG ĐƯỢC DÙNG. Còn lại ở đây như một ví dụ về những gì không hoạt động.

Thực sự hữu ích khi biết rằng không có dấu ngoặc kép nào trong một chuỗi JSON. Giả sử, bạn đã sao chép và dán nó từ bảng điều khiển trình duyệt / bất cứ thứ gì. Sau đó, bạn chỉ cần nhập

a = json.loads('very_long_json_string_pasted_here')

Nếu không, điều này có thể bị phá vỡ nếu nó cũng sử dụng dấu ngoặc kép.


2
không đúng là không có dấu ngoặc kép nào trong một chuỗi json. Điều đó có thể đúng trong một trường hợp cụ thể, nhưng bạn không thể dựa vào nó. ví dụ: đây là json hợp lệ:{"key": "value 'with' single quotes"}
Jiaaro

2

Nó thực sự giải quyết được vấn đề của tôi bằng cách sử dụng hàm eval.

single_quoted_dict_in_string = "{'key':'value', 'key2': 'value2'}"
desired_double_quoted_dict = eval(single_quoted_dict_in_string)
# Go ahead, now you can convert it into json easily
print(desired_double_quoted_dict)

Đây là một ví dụ rất tệ. Điều gì sẽ xảy ra nếu ai đó phát hiện ra bạn đang sử dụng eval trên json và gửi một mã chứa json không đúng định dạng sau đó được đánh giá bằng eval?
Metonymy

1

Gần đây tôi đã đưa ra một vấn đề tương tự và tin rằng giải pháp của tôi cũng sẽ phù hợp với bạn. Tôi đã có một tệp văn bản chứa danh sách các mục trong biểu mẫu:

["first item", 'the "Second" item', "thi'rd", 'some \\"hellish\\" \'quoted" item']

Tôi muốn phân tích cú pháp ở trên thành danh sách python nhưng không quan tâm đến eval () vì tôi không thể tin tưởng đầu vào. Đầu tiên tôi đã thử sử dụng JSON nhưng nó chỉ chấp nhận các mục được trích dẫn kép, vì vậy tôi đã viết bộ lexer rất đơn giản của riêng mình cho trường hợp cụ thể này (chỉ cần cắm "stringtoparse" của riêng bạn và bạn sẽ nhận được dưới dạng danh sách đầu ra: 'items')

#This lexer takes a JSON-like 'array' string and converts single-quoted array items into escaped double-quoted items,
#then puts the 'array' into a python list
#Issues such as  ["item 1", '","item 2 including those double quotes":"', "item 3"] are resolved with this lexer
items = []      #List of lexed items
item = ""       #Current item container
dq = True       #Double-quotes active (False->single quotes active)
bs = 0          #backslash counter
in_item = False #True if currently lexing an item within the quotes (False if outside the quotes; ie comma and whitespace)
for c in stringtoparse[1:-1]:   #Assuming encasement by brackets
    if c=="\\": #if there are backslashes, count them! Odd numbers escape the quotes...
        bs = bs + 1
        continue                    
    if (dq and c=='"') or (not dq and c=="'"):  #quote matched at start/end of an item
        if bs & 1==1:   #if escaped quote, ignore as it must be part of the item
            continue
        else:   #not escaped quote - toggle in_item
            in_item = not in_item
            if item!="":            #if item not empty, we must be at the end
                items += [item]     #so add it to the list of items
                item = ""           #and reset for the next item
            continue                
    if not in_item: #toggle of single/double quotes to enclose items
        if dq and c=="'":
            dq = False
            in_item = True
        elif not dq and c=='"':
            dq = True
            in_item = True
        continue
    if in_item: #character is part of an item, append it to the item
        if not dq and c=='"':           #if we are using single quotes
            item += bs * "\\" + "\""    #escape double quotes for JSON
        else:
            item += bs * "\\" + c
        bs = 0
        continue

Hy vọng rằng nó hữu ích cho ai đó. Thưởng thức!


Điều này cung cấp những gì bạn không nhận được từ docs.python.org/2/library/ast.html#ast.literal_eval ?
Charles Duffy

0
import ast 
answer = subprocess.check_output(PYTHON_ + command, shell=True).strip()
    print(ast.literal_eval(answer.decode(UTF_)))

Làm việc cho tôi


-4
import json
data = json.dumps(list)
print(data)

Đoạn mã trên sẽ hoạt động.


2
Nó có thể làm điều gì đó hữu ích, nhưng nó không trả lời câu hỏi đã được đặt ra. Vấn đề bắt đầu với một chuỗi, không phải một danh sách.
Rachel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.