Einfache oder doppelte Anführungszeichen in JSON

105

Mein Code:

import simplejson as json

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

#1 Definition ist falsch

#2 Definition ist richtig

Ich habe gehört, dass in Python dieses einfache und doppelte Anführungszeichen austauschbar sein können. Kann mir das jemand erklären?

Bin Chen
quelle

Antworten:

167

JSON-Syntax ist keine Python-Syntax. JSON erfordert doppelte Anführungszeichen für seine Zeichenfolgen.

Ignacio Vazquez-Abrams
quelle
2
Aber zuerst ist es ein einfaches Zitat in JSON, ich bin verwirrt. Dieser kann die Kompilierung bestehen, der zweite jedoch nicht.
Bin Chen
6
Vielen Dank für diese Bestätigung. Anscheinend bin ich der einzige, der importiert str(dict)und will es nicht eval. Ein einfacher .replace("'", '"')sollte den Trick machen.
isaaclw
8
Und ich habe zu früh gesprochen. Anscheinend ist es komplizierter.
isaaclw
6
Wenn Sie überall doppelte Anführungszeichen verwenden müssen, können Sie json.dumps(..)zweimal anrufen wie in: import json; d = dict(tags=["dog", "cat", "mouse"]); print json.dumps(json.dumps(d))was ergibt:"{\"tags\": [\"dog\", \"cat\", \"mouse\"]}"
rprasad
122

Sie können verwenden ast.literal_eval()

>>> import ast
>>> s = "{'username':'dfdsfdsf'}"
>>> ast.literal_eval(s)
{'username': 'dfdsfdsf'}
hahakubile
quelle
8
Diese Antwort gefällt mir am besten: Sie haben nicht oft die Wahl: Wenn Ihnen jemand einfache Anführungszeichen gibt, haben Sie einfache Anführungszeichen. Entweder benötigt json.loads ein zusätzliches Argument, oder Sie sollten dieses verwenden. Das globale Ersetzen von "'" ist eine Katastrophe, als ob die eingehenden Daten wie folgt { 'a' : 'this "string" really isn\'t!!!!' }
lauten
@Mark, kann diese Methode an eine schwierigere Situation mit verschachtelten Anführungszeichen angepasst werden, z "{'link':'<a href="mylink">http://my.com</a>'}". In diesem Fall ast.literal_evalwirft Syntaxfehler
alancalvitti
1
Dies scheint mir ein Sicherheitsrisiko zu sein.
Jackson
1
Wie beantwortet dies die Frage? Was hat dies mit einfachen oder doppelten Anführungszeichen in JSON zu tun? Mit diesem ast-Ansatz können Sie ein Python-Diktat aus einer Zeichenfolge laden. Das Hauptproblem des OP besteht jedoch darin, dass Zeichenfolge Nr. 1 kein gültiger JSON-Code ist, während Zeichenfolge Nr. 2 gültig ist.
jschultz410
42

Sie können JSON mit doppeltem Anführungszeichen ausgeben, indem Sie:

import json

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

# get string with all double quotes
json_string = json.dumps(data) 
Cowboybkit
quelle
12
das geht in die falsche Richtung. Sie serialisieren Python-Datenstrukturen in JSON. Die ursprüngliche Frage betrifft die Deserialisierung von JSON in Python-Datenstrukturen.
Tedder42
4
Die Idee wäre, die Python mit json.dumps in json zu serialisieren und dann json.loads darauf aufzurufen, wenn sie in der str-Form vorliegt.
Jheld
3
Sie vermissen es hier zu verstehen. Wenn Sie einen JSON-String laden möchten, muss es sich um ein doppeltes Anführungszeichen handeln. Was Sie tun, ist immer noch Dump Json, nicht Json String.
LegitMe
11

demjson ist auch ein gutes Paket, um das Problem der schlechten json-Syntax zu lösen:

pip install demjson

Verwendung:

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

Bearbeiten:

demjson.decodeist ein großartiges Tool für beschädigten JSON, aber wenn Sie mit einer großen Menge von JSON-Daten zu tun haben, ast.literal_evalist dies eine bessere Übereinstimmung und viel schneller.

DhiaTN
quelle
4
demjson.decodeist ein großartiges Tool für beschädigten JSON - aber für Aufgaben mit Zehntausenden oder Hunderttausenden von JSON-Paketen ast.literal_evalist es viel schneller. Um nicht zu sagen, es demjsonhat keinen Platz: Ich benutze es als Fallback für den Fall, dass schnellere Methoden fehlschlagen.
mjwunderlich
1
Eigentlich ist Demjson einer, der viel besser funktioniert, anstatt gegen ast.literal_eval und json.loads zu testen
Marware
4

Bisher zwei Probleme mit Antworten, wenn beispielsweise eines solche nicht standardmäßige JSON-Streams überträgt. Denn dann muss man möglicherweise eine eingehende Zeichenfolge interpretieren (kein Python-Wörterbuch).

demjsonProblem 1 - : Mit Python 3.7. + Und unter Verwendung von conda konnte ich demjson nicht installieren, da Python> 3.5 derzeit offensichtlich nicht unterstützt wird. Ich brauche also eine Lösung mit einfacheren Mitteln, zum Beispiel astund / oderjson.dumps .

Problem 2 - ast& json.dumps: Wenn ein JSON in einfachen Anführungszeichen steht und eine Zeichenfolge in mindestens einem Wert enthält, der wiederum einfache Anführungszeichen enthält, besteht die einzige einfache und dennoch praktische Lösung darin, beide anzuwenden:

Im folgenden Beispiel nehmen wir an, dass linees sich um das eingehende JSON-Zeichenfolgenobjekt handelt:

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

Schritt 1: Konvertieren Sie die eingehende Zeichenfolge mithilfe von ast.literal_eval()
Schritt 2 in ein Wörterbuch. Wenden json.dumpsSie darauf die zuverlässige Konvertierung von Schlüsseln und Werten an, ohne jedoch den Inhalt von Werten zu berühren :

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

json.dumpsallein würde den Job nicht machen, weil es den JSON nicht interpretiert, sondern nur den String sieht. Ähnliches gilt für ast.literal_eval(): Obwohl es das JSON (Wörterbuch) korrekt interpretiert, konvertiert es nicht das, was wir brauchen.

Siegfried Heide
quelle
3

Sie können dies folgendermaßen beheben:

s = "{'username':'dfdsfdsf'}"
j = eval(s)
Robin Ali
quelle
Verwenden Sie ast.literal_eval anstelle von eval, um Injektionsangriffe zu vermeiden
Simon Kingaby
2

Wie gesagt, JSON ist keine Python-Syntax. Sie müssen in JSON doppelte Anführungszeichen verwenden. Sein Schöpfer ist (un) berühmt dafür, strenge Teilmengen der zulässigen Syntax zu verwenden, um die kognitive Überlastung des Programmierers zu verringern.


Das Folgende kann fehlschlagen, wenn eine der JSON-Zeichenfolgen selbst ein einfaches Anführungszeichen enthält, wie von @Jiaaro hervorgehoben. VERWENDE NICHT. Links hier als Beispiel für das, was nicht funktioniert.

Es ist sehr nützlich zu wissen, dass eine JSON-Zeichenfolge keine einfachen Anführungszeichen enthält. Angenommen, Sie haben es von einer Browserkonsole / was auch immer kopiert und eingefügt. Dann können Sie einfach tippen

a = json.loads('very_long_json_string_pasted_here')

Dies könnte sonst brechen, wenn auch einfache Anführungszeichen verwendet werden.

serv-inc
quelle
2
Es ist nicht wahr, dass eine JSON-Zeichenfolge keine einfachen Anführungszeichen enthält. Das mag in einem bestimmten Fall zutreffen, aber Sie können sich nicht darauf verlassen. zB ist dies gültig json:{"key": "value 'with' single quotes"}
Jiaaro
2

Es hat mein Problem mit der Bewertungsfunktion wirklich gelöst.

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)
Hafiz Hashim
quelle
Dies ist ein sehr schlechtes Beispiel. Was ist, wenn jemand herausfindet, dass Sie eval auf json verwenden, und einen fehlerhaften json mit Code sendet, der dann von eval ausgewertet wird?
Metonymie
1

Ich bin kürzlich auf ein sehr ähnliches Problem gestoßen und glaube, dass meine Lösung auch für Sie funktionieren würde. Ich hatte eine Textdatei, die eine Liste der Elemente im Formular enthielt:

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

Ich wollte das Obige in eine Python-Liste zerlegen, war aber nicht an eval () interessiert, da ich der Eingabe nicht vertrauen konnte. Ich habe zuerst versucht, JSON zu verwenden, aber es werden nur Elemente in doppelten Anführungszeichen akzeptiert. Daher habe ich meinen eigenen, sehr einfachen Lexer für diesen speziellen Fall geschrieben.

#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

Hoffentlich ist es jemandem nützlich. Genießen!

Matt
quelle
Was bietet Ihnen dies nicht von 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_)))

Funktioniert bei mir

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

Das obige Code-Snippet sollte funktionieren.

Dheeraj R.
quelle
2
Es kann etwas Nützliches tun, aber es beantwortet nicht die gestellte Frage. Das Problem beginnt mit einer Zeichenfolge, nicht mit einer Liste.
Rachel