Odpowiedzi:
Składnia JSON nie jest składnią Pythona. JSON wymaga podwójnych cudzysłowów dla swoich ciągów.
str(dict)i nie chcę evaltego. Prosty .replace("'", '"')powinien załatwić sprawę.
json.dumps(..)dwukrotnie, tak jak w: import json; d = dict(tags=["dog", "cat", "mouse"]); print json.dumps(json.dumps(d))co daje:"{\"tags\": [\"dog\", \"cat\", \"mouse\"]}"
możesz użyć ast.literal_eval()
>>> import ast
>>> s = "{'username':'dfdsfdsf'}"
>>> ast.literal_eval(s)
{'username': 'dfdsfdsf'}
{ 'a' : 'this "string" really isn\'t!!!!' }
"{'link':'<a href="mylink">http://my.com</a>'}"? W tym przypadku ast.literal_evalzgłasza błąd składni
Możesz zrzucić JSON z podwójnym cudzysłowem przez:
import json
# mixing single and double quotes
data = {'jsonKey': 'jsonValue',"title": "hello world"}
# get string with all double quotes
json_string = json.dumps(data)
demjson to także dobry pakiet do rozwiązania problemu złej składni json:
pip install demjson
Stosowanie:
from demjson import decode
bad_json = "{'username':'dfdsfdsf'}"
python_dict = decode(bad_json)
Edytować:
demjson.decodejest świetnym narzędziem do uszkodzonego json, ale gdy masz do czynienia z dużą ilością danych json,ast.literal_evaljest to lepsze dopasowanie i znacznie szybsze.
demjson.decodejest doskonałym narzędziem do uszkodzonego json - ale w przypadku zadań obejmujących dziesiątki lub setki tysięcy pakietów json ast.literal_evaljest znacznie szybsze. Nie znaczy demjsonto , że nie ma swojego miejsca: używam go jako rezerwy na wypadek, gdyby szybsze metody zawiodły.
Dwa problemy z udzielonymi dotychczas odpowiedziami, jeśli na przykład jeden z nich przesyła taki niestandardowy JSON. Ponieważ wtedy należałoby zinterpretować przychodzący ciąg znaków (nie słownik Pythona).
Problem 1 - demjson: Z Pythonem 3.7. + I przy użyciu Conda nie mogłem zainstalować demjsona, ponieważ oczywiście obecnie nie obsługuje on Pythona> 3.5. Więc potrzebuję rozwiązania z prostszymi środkami, na przykład asti / lub json.dumps.
Problem 2 - ast& json.dumps: Jeśli JSON jest zarówno w apostrofach, jak i zawiera ciąg w co najmniej jednej wartości, która z kolei zawiera pojedyncze cudzysłowy, jedynym prostym, ale praktycznym rozwiązaniem, które znalazłem, jest zastosowanie obu:
W poniższym przykładzie zakładamy, że linejest to przychodzący obiekt ciągu JSON:
>>> line = str({'abc':'008565','name':'xyz','description':'can control TV\'s and more'})
Krok 1: przekonwertuj przychodzący ciąg znaków na słownik za pomocą ast.literal_eval()
kroku 2: zastosuj się json.dumpsdo niego, aby zapewnić niezawodną konwersję kluczy i wartości, ale bez dotykania zawartości wartości :
>>> import ast
>>> import json
>>> print(json.dumps(ast.literal_eval(line)))
{"abc": "008565", "name": "xyz", "description": "can control TV's and more"}
json.dumpssam nie wykonałby zadania, ponieważ nie interpretuje JSON, a widzi tylko ciąg. Podobnie ast.literal_eval(): chociaż poprawnie interpretuje JSON (słownik), nie konwertuje tego, czego potrzebujemy.
Możesz to naprawić w ten sposób:
s = "{'username':'dfdsfdsf'}"
j = eval(s)
Jak powiedziałem, JSON nie jest składnią Pythona. Musisz użyć podwójnych cudzysłowów w JSON. Jego twórca jest (nie) znany z używania ścisłych podzbiorów dopuszczalnej składni, aby złagodzić przeciążenie poznawcze programisty.
Poniżej może się nie powieść, jeśli jeden z ciągów JSON zawiera pojedynczy cudzysłów, jak wskazał @Jiaaro. NIE UŻYWAĆ. Zostawiłem tutaj jako przykład tego, co nie działa.
Jest to bardzo przydatne, aby wiedzieć, że nie istnieją pojedyncze cudzysłowy w ciąg JSON. Powiedzmy, że skopiowałeś i wkleiłeś go z konsoli przeglądarki / cokolwiek. Następnie możesz po prostu wpisać
a = json.loads('very_long_json_string_pasted_here')
W przeciwnym razie może się to zepsuć, jeśli użyje również pojedynczych cudzysłowów.
{"key": "value 'with' single quotes"}
Naprawdę rozwiązał mój problem za pomocą funkcji 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)
Niedawno natknąłem się na bardzo podobny problem i uważam, że moje rozwiązanie zadziała również dla Ciebie. Miałem plik tekstowy, który zawierał listę pozycji w postaci:
["first item", 'the "Second" item', "thi'rd", 'some \\"hellish\\" \'quoted" item']
Chciałem przeanalizować powyższe do listy Pythona, ale nie przepadałem za eval (), ponieważ nie mogłem ufać wejściu. Próbowałem najpierw użyć JSON, ale akceptuje tylko elementy w podwójnych cudzysłowach, więc napisałem własny, bardzo prosty lekser dla tego konkretnego przypadku (po prostu podłącz swój własny „stringtoparse”, a otrzymasz jako listę wyników: „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
Mam nadzieję, że komuś się to przyda. Cieszyć się!
import ast
answer = subprocess.check_output(PYTHON_ + command, shell=True).strip()
print(ast.literal_eval(answer.decode(UTF_)))
Pracuje dla mnie