Virgolette singole e doppie in JSON


108

Il mio codice:

import simplejson as json

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

#1 la definizione è sbagliata

#2 la definizione è giusta

Ho sentito che in Python quella virgoletta singola e quella doppia possono essere intercambiabili. Qualcuno può spiegarmi questo?

Risposte:


170

La sintassi JSON non è la sintassi Python. JSON richiede virgolette doppie per le sue stringhe.


2
ma la prima è una citazione singola in JSON, sono confuso. Quello può passare alla compilazione ma il secondo no.
Bin Chen

6
Grazie per questa conferma. Apparentemente sono l'unico che importa str(dict)e non voglio evalfarlo. Un semplice .replace("'", '"')dovrebbe fare il trucco.
isaaclw

8
E ho parlato troppo presto. Apparentemente è più complicato di così.
isaaclw

6
Se è necessario utilizzare virgolette doppie json.dumps(..)import json; d = dict(tags=["dog", "cat", "mouse"]); print json.dumps(json.dumps(d))"{\"tags\": [\"dog\", \"cat\", \"mouse\"]}"
ovunque

124

Puoi usare ast.literal_eval()

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

9
Questa risposta mi piace di più: spesso non hai scelta: se qualcuno ti dà virgolette singole, hai virgolette singole. O json.loads necessita di un argomento in più, oppure dovresti usarlo. La sostituzione globale di "'" è un disastro, come se i dati in arrivo fossero:{ 'a' : 'this "string" really isn\'t!!!!' }
Mark Gerolimatos

@Mark, questo metodo può essere adattato a una situazione più complicata con virgolette annidate, ad esempio "{'link':'<a href="mylink">http://my.com</a>'}"? In questo caso, ast.literal_evalgenera un errore di sintassi
alancalvitti

1
Questo mi sembra un rischio per la sicurezza.
JacksonHaenchen

2
Come risponde questo alla domanda? Cosa ha a che fare con virgolette singole e doppie in JSON? Questo approccio astuto potrebbe consentire di caricare un dict Python da una stringa, ma il problema principale dell'OP è che la stringa # 1 non è JSON valido mentre la stringa # 2 lo è.
jschultz410

43

Puoi scaricare JSON con virgolette doppie:

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
questo va nel modo sbagliato. stai serializzando strutture dati Python in JSON; la domanda originale riguarda la deserializzazione di JSON in strutture di dati Python.
voltafieno42

5
L'idea sarebbe quella di serializzare il python in json con json.dumps, quindi chiamare json.loads su di esso quando è nella forma str.
tenuto il

3
Ti manca capire qui. Se vuoi caricare la stringa json, deve essere virgolette doppie. Quello che stai facendo è ancora scaricare json, non la stringa json.
LegitMe

12

demjson è anche un buon pacchetto per risolvere il problema della cattiva sintassi json:

pip install demjson

Utilizzo:

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

Modificare:

demjson.decodeè un ottimo strumento per json danneggiato, ma quando hai a che fare con una grande quantità di dati json ast.literal_evalè una corrispondenza migliore e molto più veloce.


4
demjson.decodeè un ottimo strumento per json danneggiato, ma per attività che coinvolgono decine o centinaia di migliaia di pacchetti json, ast.literal_evalè molto più veloce. Per demjsonnon dire che non ha il suo posto: lo uso come riserva nel caso in cui i metodi più veloci falliscano.
mjwunderlich

1
In realtà demjson ha funzionato molto meglio, invece di testare contro ast.literal_eval e json.loads
Marware

4

Due problemi con le risposte fornite finora, se, ad esempio, si trasmette un JSON non standard. Perché allora si potrebbe dover interpretare una stringa in arrivo (non un dizionario Python).

Problema 1 - demjson: con Python 3.7. + E utilizzando conda non sono stato in grado di installare demjson poiché ovviamente non supporta attualmente Python> 3.5. Quindi ho bisogno di una soluzione con mezzi più semplici, ad esempio aste / o json.dumps.

Problema 2 - ast& json.dumps: Se un JSON è sia virgolato singolo che contiene una stringa in almeno un valore, che a sua volta contiene virgolette singole, l'unica soluzione semplice ma pratica che ho trovato è applicare entrambi:

Nell'esempio seguente si presume linesia l'oggetto stringa JSON in arrivo:

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

Passaggio 1: convertire la stringa in arrivo in un dizionario utilizzando ast.literal_eval()
Passaggio 2: applicare json.dumpsad essa per la conversione affidabile di chiavi e valori, ma senza toccare il contenuto dei valori :

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

json.dumpsda solo non farebbe il lavoro perché non interpreta il JSON, ma vede solo la stringa. Simile per ast.literal_eval(): sebbene interpreti correttamente il JSON (dizionario), non converte ciò di cui abbiamo bisogno.


3

Puoi aggiustarlo in questo modo:

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

usa ast.literal_eval invece di eval per evitare attacchi di iniezione
Simon Kingaby il

2

Come detto, JSON non è la sintassi di Python. Devi usare le virgolette doppie in JSON. Il suo creatore è (ins) famoso per l'utilizzo di sottoinsiemi rigorosi di sintassi consentita per alleviare il sovraccarico cognitivo del programmatore.


Di seguito può non riuscire se una delle stringhe JSON stessa contiene una singola virgoletta, come sottolineato da @Jiaaro. NON USARE. Lasciato qui come esempio di ciò che non funziona.

È davvero utile sapere che non ci sono virgolette singole in una stringa JSON. Diciamo, lo hai copiato e incollato da una console del browser / qualunque cosa. Quindi, puoi semplicemente digitare

a = json.loads('very_long_json_string_pasted_here')

Questo potrebbe altrimenti rompersi se usasse anche virgolette singole.


2
non è vero che non ci sono virgolette singole in una stringa json. Potrebbe essere vero in un caso specifico, ma non puoi fare affidamento su di esso. ad esempio, questo è json valido:{"key": "value 'with' single quotes"}
Jiaaro

2

Ha veramente risolto il mio problema usando la funzione 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)

Questo è un pessimo esempio. Cosa succede se qualcuno scopre che stai usando eval su json e invia un json non valido contenente codice che viene quindi valutato da eval?
Metonimia

1

Di recente mi sono imbattuto in un problema molto simile e credo che la mia soluzione funzionerebbe anche per te. Avevo un file di testo che conteneva un elenco di elementi nel modulo:

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

Volevo analizzare quanto sopra in un elenco di python ma non ero appassionato di eval () perché non potevo fidarmi dell'input. Ho provato prima a usare JSON ma accetta solo elementi con virgolette doppie, quindi ho scritto il mio lexer molto semplice per questo caso specifico (basta inserire il tuo "stringtoparse" e otterrai come elenco di output: '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

Si spera che sia utile a qualcuno. Godere!


Cosa fornisce questo non si ottiene da 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_)))

Per me va bene


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

Lo snippet di codice sopra dovrebbe funzionare.


2
Può fare qualcosa di utile, ma non risponde alla domanda che è stata posta. Il problema inizia con una stringa, non con un elenco.
Rachel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.