Respostas:
A sintaxe JSON não é sintaxe Python. JSON requer aspas duplas para suas strings.
str(dict)
e não quero eval
. Um simples .replace("'", '"')
deve resolver o problema.
json.dumps(..)
duas vezes como em: o import json; d = dict(tags=["dog", "cat", "mouse"]); print json.dumps(json.dumps(d))
que dá:"{\"tags\": [\"dog\", \"cat\", \"mouse\"]}"
você pode usar 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>'}"
? Nesse caso, ast.literal_eval
gera um erro de sintaxe
Você pode descartar JSON com aspas duplas:
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 também é um bom pacote para resolver o problema de sintaxe json inválida:
pip install demjson
Uso:
from demjson import decode
bad_json = "{'username':'dfdsfdsf'}"
python_dict = decode(bad_json)
Editar:
demjson.decode
é uma ótima ferramenta para json danificado, mas quando você está lidando com uma grande área de dados jsonast.literal_eval
é uma combinação melhor e muito mais rápida.
demjson.decode
é uma ótima ferramenta para json danificado - mas para tarefas que envolvem dezenas ou centenas de milhares de pacotes json, ast.literal_eval
é muito mais rápido. Para não dizer demjson
que não tem o seu lugar: eu o uso como fallback caso métodos mais rápidos falhem.
Dois problemas com as respostas dadas até agora, se, por exemplo, um transmitir tal JSON não padrão. Porque então pode ser necessário interpretar uma string de entrada (não um dicionário python).
Problema 1 - demjson
: Com Python 3.7. + E usando conda, não consegui instalar o demjson, pois obviamente ele não oferece suporte a Python> 3.5 atualmente. Portanto, preciso de uma solução com meios mais simples, por exemplo ast
e / ou json.dumps
.
Problema 2 - ast
& json.dumps
: Se um JSON tem aspas simples e contém uma string em pelo menos um valor, que por sua vez contém aspas simples, a única solução simples, porém prática, que encontrei é aplicar ambos:
No exemplo a seguir, supomos que line
seja o objeto de string JSON de entrada:
>>> line = str({'abc':'008565','name':'xyz','description':'can control TV\'s and more'})
Etapa 1: converta a string de entrada em um dicionário usando a ast.literal_eval()
Etapa 2: aplique json.dumps
a ela para a conversão confiável de chaves e valores, mas sem tocar no conteúdo dos valores :
>>> import ast
>>> import json
>>> print(json.dumps(ast.literal_eval(line)))
{"abc": "008565", "name": "xyz", "description": "can control TV's and more"}
json.dumps
sozinho não faria o trabalho porque não interpreta o JSON, mas apenas vê a string. Semelhante para ast.literal_eval()
: embora interprete corretamente o JSON (dicionário), ele não converte o que precisamos.
Você pode consertar assim:
s = "{'username':'dfdsfdsf'}"
j = eval(s)
Como disse, JSON não é sintaxe Python. Você precisa usar aspas duplas em JSON. Seu criador é (in) famoso por usar subconjuntos estritos de sintaxe permitida para facilitar a sobrecarga cognitiva do programador.
Abaixo pode falhar se uma das strings JSON contiver uma aspa simples, conforme apontado por @Jiaaro. NÃO USE. Deixado aqui como exemplo do que não funciona.
É muito útil saber que não há aspas simples em uma string JSON. Digamos, você copiou e colou de um console de navegador / qualquer coisa. Então, você pode simplesmente digitar
a = json.loads('very_long_json_string_pasted_here')
Caso contrário, isso poderia falhar se também usasse aspas simples.
{"key": "value 'with' single quotes"}
Ele realmente resolveu meu problema usando a função 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)
Recentemente me deparei com um problema muito semelhante e acredito que minha solução funcionaria para você também. Eu tinha um arquivo de texto que continha uma lista de itens no formulário:
["first item", 'the "Second" item', "thi'rd", 'some \\"hellish\\" \'quoted" item']
Eu queria analisar o acima em uma lista python, mas não estava interessado em eval () porque não podia confiar na entrada. Tentei primeiro usar JSON, mas ele só aceita itens com aspas duplas, então escrevi meu próprio lexer muito simples para este caso específico (basta conectar seu próprio "stringtoparse" e você obterá como lista de saída: 'itens')
#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
Espero que seja útil para alguém. Aproveitar!
import ast
answer = subprocess.check_output(PYTHON_ + command, shell=True).strip()
print(ast.literal_eval(answer.decode(UTF_)))
Funciona para mim