Python: json.loads devuelve elementos con el prefijo 'u'

161

Recibiré una forma de cadena codificada JSON Obj-C, y estoy decodificando una cadena ficticia (por ahora) como el código a continuación. Mi salida sale con el carácter 'u' que antepone cada elemento:

[{u'i': u'imap.gmail.com', u'p': u'aaaa'}, {u'i': u'333imap.com', u'p': u'bbbb'}...

¿Cómo está JSON agregando este char unicode? ¿Cuál es la mejor manera de eliminarlo?

mail_accounts = []
da = {}
try:
    s = '[{"i":"imap.gmail.com","p":"aaaa"},{"i":"imap.aol.com","p":"bbbb"},{"i":"333imap.com","p":"ccccc"},{"i":"444ap.gmail.com","p":"ddddd"},{"i":"555imap.gmail.com","p":"eee"}]'
    jdata = json.loads(s)
    for d in jdata:
        for key, value in d.iteritems():
            if key not in da:
                da[key] = value
            else:
                da = {}
                da[key] = value
        mail_accounts.append(da)
except Exception, err:
    sys.stderr.write('Exception Error: %s' % str(err))

print mail_accounts
janeh
fuente
77
Python tiene un problema aquí. No todo es frío. Recibo errores en las cadenas que Python crea cuando intento escribir estas cadenas en un archivo. Por ejemplo, cuando python toma "53" de JSON, lo convierte en u'53 'e intenta escribirlo en un archivo como carácter hexadecimal u' \ xe1 ', lo que hace que Python tome una cadena perfectamente buena y vomite sobre ella: JSON: {"sa_BstDeAv": "53", "sa_BwVUpMx" ... PYTHON: {u'sa_BstDeAv ': u'53', u'sa_BwVUpMx '... ERROR AL ESCRIBIR: Error de valor (el códec' ascii 'no puede codificar carácter u '\ xe1' en la posición 5: ordinal no en el rango (128))
David Urry
@janehouse la respuesta correcta aquí es la respuesta de jdi Realmente creo que deberías cambiarla.
Dekel

Respuestas:

168

El prefijo u solo significa que tiene una cadena Unicode. Cuando realmente use la cadena, no aparecerá en sus datos. No se deje llevar por la salida impresa.

Por ejemplo, intente esto:

print mail_accounts[0]["i"]

No verás una u.

Ned Batchelder
fuente
55
Su respuesta fue la más útil que obtuve, y creo que el que hizo esta pregunta realmente lo habría apreciado: stackoverflow.com/questions/956867/…
jimh
1
Muchas gracias ! estaba confundido por ti '' carta por tanto tiempo
ketan khandagale
Excepto si lo copia y lo pega, tiene una gran cantidad de us en sus datos. Francamente, imprimir una upara indicar que es una cadena Unicode es uno de los peores errores sobre Python. Absolutamente ridículo. ¿Por qué no imprimir un aantes de cada cadena si es ASCII? ¿Y isi es un número entero?
Snowcrash
En Python 2, las cadenas Unicode son de un tipo diferente que las cadenas de bytes, por lo que la reproducción de los datos incluye el prefijo para indicar eso. No se trata del contenido, sino del tipo. El prefijo u está bien si está pegando el contenido nuevamente en un programa Python. Si no, tal vez quieras usar json.dumps () en su lugar.
Ned Batchelder
Tienes que usar la cadena para buscar el diccionario de json. Sin embargo, no puede utilizar el operador de puntos.
Maddocks
151

Todo está bien, hombre. La 'u' es algo bueno, indica que la cadena es de tipo Unicode en python 2.x.

http://docs.python.org/2/howto/unicode.html#the-unicode-type

Un hombre
fuente
71
Me gusta el tono muy relajado de este. +1 por una respuesta (correcta) que me hizo sonreír.
mgilson
19
Just, chill ... (┛◉Д◉) ┛ 彡 ┻━┻
fulvio
31
Esa fue la respuesta más relajante que he leído en StackOverflow.
aanrv
3
☮ ☮ ☮ Paz ☮ ☮ ☮
sr9yar
54

La d3impresión a continuación es la que está buscando (que es la combinación de volcados y cargas) :)

Teniendo:

import json

d = """{"Aa": 1, "BB": "blabla", "cc": "False"}"""

d1 = json.loads(d)              # Produces a dictionary out of the given string
d2 = json.dumps(d)              # Produces a string out of a given dict or string
d3 = json.dumps(json.loads(d))  # 'dumps' gets the dict from 'loads' this time

print "d1:  " + str(d1)
print "d2:  " + d2
print "d3:  " + d3

Huellas dactilares:

d1:  {u'Aa': 1, u'cc': u'False', u'BB': u'blabla'}
d2:  "{\"Aa\": 1, \"BB\": \"blabla\", \"cc\": \"False\"}"
d3:  {"Aa": 1, "cc": "False", "BB": "blabla"}
Mercurio
fuente
3
¿Eh? json.dumpsconvierte el dict nuevamente en una cadena (codificada con JSON). Eso no es lo que el OP quería hacer. -1.
Mark Amery
10
Pero si lo usa junto con json.loads, genera el diccionario sin los caracteres codificados, lo que es una respuesta a la pregunta (esta es la impresión d3 anterior) ¡lea bien la respuesta!
Mercurio
8

El uprefijo significa que esas cadenas son unicode en lugar de cadenas de 8 bits. La mejor manera de no mostrar el uprefijo es cambiar a Python 3, donde las cadenas son unicode por defecto. Si esa no es una opción, el strconstructor convertirá de unicode a 8 bits, así que simplemente haga un bucle recursivo sobre el resultado y convierta unicodea str. Sin embargo, probablemente sea mejor dejar las cadenas como unicode.

Abe Karplus
fuente
8

Unicode es un tipo apropiado aquí. Los documentos de JSONDecoder describen la tabla de conversión y establecen que los objetos de cadena json se decodifican en objetos Unicode

https://docs.python.org/2/library/json.html#encoders-and-decoders

JSON                    Python
==================================
object                  dict
array                   list
string                  unicode
number (int)            int, long
number (real)           float
true                    True
false                   False
null                    None

"la codificación determina la codificación utilizada para interpretar cualquier objeto str decodificado por esta instancia (UTF-8 por defecto)".

jdi
fuente
7

Esos caracteres 'u' que se agregan a un objeto significa que el objeto está codificado en "unicode".

Si desea eliminar esos caracteres 'u' de su objeto, puede hacer esto:

import json, ast
jdata = ast.literal_eval(json.dumps(jdata)) # Removing uni-code chars

Hagamos el pago desde Python Shell

>>> import json, ast
>>> jdata = [{u'i': u'imap.gmail.com', u'p': u'aaaa'}, {u'i': u'333imap.com', u'p': u'bbbb'}]
>>> jdata = ast.literal_eval(json.dumps(jdata))
>>> jdata
[{'i': 'imap.gmail.com', 'p': 'aaaa'}, {'i': '333imap.com', 'p': 'bbbb'}]
Nivesh Krishna
fuente
Sugiero que todos los novatos simplemente prueben este script y listo, tienen un script para convertir ~ desde ~ la salida de u'JSON :) ... si uno solo puede agregar stdin al script y el formato json al final, está ¡Listo para ir!
Jordan Gee
4

Me encontré con este problema al intentar capturar datos JSON en el registro con la loggingbiblioteca de Python , para fines de depuración y solución de problemas. Obtener el upersonaje es una verdadera molestia cuando quieres copiar el texto y pegarlo en tu código en alguna parte.

Como todo el mundo le dirá, esto se debe a que es una representación Unicode y, json.loads()en primer lugar , podría deberse al hecho de que ha utilizado para cargar los datos de una cadena.

Si desea la representación JSON en el registro, sin el uprefijo, el truco es usar json.dumps()antes de cerrar la sesión. Por ejemplo:

import json
import logging

# Prepare the data
json_data = json.loads('{"key": "value"}')

# Log normally and get the Unicode indicator
logging.warning('data: {}'.format(json_data))
>>> WARNING:root:data: {u'key': u'value'}

# Dump to a string before logging and get clean output!
logging.warning('data: {}'.format(json.dumps(json_data)))
>>> WARNING:root:data: {'key': 'value'}
jonatan
fuente
1
Esta realmente debería ser la mejor respuesta, los 'u' no "simplemente se despojan" en muchos contextos. muchas gracias por esto!
Jessica Pennell
1

Prueba esto:

mail_accounts [0] .encode ("ascii")

2nd Sight Lab
fuente
Una respuesta sin ninguna explicación es casi inútil. Intenta agregar información como por qué esto ayudaría.
Abhilash Chandran
Personalmente, encuentro respuestas largas con demasiada información innecesaria que me distrae. Las respuestas anteriores ya explican que el valor es unicode y debe convertirse a ascii, por lo que no estoy repitiendo todo eso. Solo muestra una forma más simple de obtener el valor. Si alguien tiene problemas para usar esta respuesta, solo pregunte y me complace explicarle más. Gracias
2nd Sight Lab
Esta es realmente la única respuesta que muestra de manera concisa cómo volver a codificar cada cadena a 'normal' sin pasar por un ciclo (lo que debe ser ridículamente ineficiente) json.loads, json.dumps.
Ed Randall
0

Simplemente reemplace la u 'con una comilla simple ...

print (str.replace(mail_accounts,"u'","'"))
Mikematic
fuente