139 votos

Cómo obtener Objetos string en lugar de Unicode de JSON en Python?

Estoy usando Python para parsear JSON (codificada en ASCII) archivos de texto. Cuando la carga de estos archivos, ya sea con json o simplejson, todos mis valores de cadena se echan a Unicode objetos en lugar de objetos string.

El problema es, que tengo uso de los datos con algunas de las bibliotecas que sólo aceptan los objetos string. No puedo cambiar las bibliotecas ni de la actualización de ellos.

Es posible conseguir objetos string en lugar de unicode de json o simplejson?

Aquí un pequeño ejemplo:

>>> import json
>>> original_list = ['a', 'b']
>>> json_list = json.dumps(original_list)
>>> json_list
'["a", "b"]'
>>> new_list = json.loads(js)
>>> new_list
[u'a', u'b'] # I want these to be of type `str`, not `unicode`

90voto

Mark Amery Puntos 4705

No hay ninguna opción integrada para hacer el json módulo de retorno de funciones de cadenas de bytes en lugar de cadenas unicode. Sin embargo, esta breve y sencilla función recursiva va a convertir cualquier decodificado objeto JSON desde el uso de cadenas unicode UTF-8 codificado cadenas de bytes:

def convert(input):
    if isinstance(input, dict):
        return {convert(key): convert(value) for key, value in input.iteritems()}
    elif isinstance(input, list):
        return [convert(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input

Simplemente llame a este en la salida que se obtiene de un json.load o json.loads de llamada.

Una nota final: para soporte de Python 2.6 o versiones anteriores, reemplace return {convert(key): convert(value) for key, value in input.iteritems()} con return dict([(convert(key), convert(value)) for key, value in input.iteritems()]), desde el diccionario de comprensión no se admite hasta Python 2.7.

89voto

Brutus Puntos 1028

Mientras que hay algunas buenas respuestas por aquí, que terminó con PyYAML para analizar los archivos, me da objetos string. Desde JSON es un subconjunto de YAML funciona muy bien en todos los casos.

>>> import json
>>> import yaml
>>> list_org = ['a', 'b']
>>> list_dump = json.dumps(list_org)
>>> list_dump
'["a", "b"]'
>>> json.loads(list_dump)
[u'a', u'b']
>>> yaml.load(list_dump)
['a', 'b']

67voto

Mike Brennan Puntos 1384

Usted puede utilizar el object_hook parámetro para json.cargas a pasar en un convertidor. Usted no tiene que hacer la conversión después del hecho. El json módulo va a pasar siempre el object_hook dicts solamente, y será de forma recursiva pasar en anidados dicts, así que usted no tiene que recurse en anidadas dicts a ti mismo. No creo que me iba a convertir cadenas unicode para los números como los Pozos de muestra. Si es una cadena unicode, fue citado como una cadena en el archivo JSON, por lo que se supone que debe ser una cadena (o el archivo está mal).

También, me gustaría tratar de evitar hacer algo como str(val) en un objeto unicode. Usted debe de valor de uso.encode(codificación) con una validez de codificación, dependiendo de lo que su externos lib espera.

Así, por ejemplo:

def _decode_list(data):
    rv = []
    for item in data:
        if isinstance(item, unicode):
            item = item.encode('utf-8')
        elif isinstance(item, list):
            item = _decode_list(item)
        elif isinstance(item, dict):
            item = _decode_dict(item)
        rv.append(item)
    return rv

def _decode_dict(data):
    rv = {}
    for key, value in data.iteritems():
        if isinstance(key, unicode):
            key = key.encode('utf-8')
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        elif isinstance(value, list):
            value = _decode_list(value)
        elif isinstance(value, dict):
            value = _decode_dict(value)
        rv[key] = value
    return rv

obj = json.loads(s, object_hook=_decode_dict)

30voto

nosklo Puntos 75862

Eso es porque json no tiene ninguna diferencia entre los objetos de cadena unicode y objetos. Están todas las cadenas en javascript.

Creo que JSON es el derecho a la devolución de objetos unicode. De hecho, yo no aceptaría nada menos, desde cadenas javascript son, de hecho, unicode objetos (es decir, JSON (javascript) secuencias pueden almacenar cualquier tipo de caracteres unicode), de modo que tiene sentido crear unicode objetos cuando la traducción de las cadenas de JSON. Las cadenas simples sólo no se ajustan desde la biblioteca tendría que adivinar la codificación que desea.

Es mejor usar unicode cadena de objetos por todas partes. Así que su mejor opción es actualizar sus bibliotecas para que puedan lidiar con unicode objetos.

Pero si realmente quieres bytestrings, justo codificar los resultados de la codificación de su elección:

>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']

9voto

Jarret Hardie Puntos 36266

Me temo que no hay manera de lograr esto de forma automática dentro de la simplejson de la biblioteca.

El escáner y el decodificador en simplejson están diseñadas para producir un texto unicode. Para ello, la biblioteca se utiliza una función llamada c_scanstring (si es que existe, para la velocidad), o py_scanstring si el C no hay disponible ninguna versión. La scanstring función es llamado varias veces por casi todas las rutinas que simplejson tiene para la decodificación de una estructura que podría contener texto. Tendrías que sea monkeypatch la scanstring valor en simplejson.decodificador o subclase JSONDecoder y proporcionan muy mucho de su propia aplicación total de cualquier cosa que pueda contener texto.

La razón por la que simplejson salidas de unicode, sin embargo, es que el json spec menciona específicamente que "Una cadena es un conjunto de cero o más caracteres Unicode"... el soporte para unicode se asume como parte del formato en sí. Simplejson del scanstring ejecución va tan lejos como para escanear e interpretar unicode escapa (incluso de comprobación de errores para con formato incorrecto multi-byte conjunto de caracteres de las representaciones), por lo que la única manera de que puedan devolver el valor que para usted es como unicode.

Si usted tiene una edad de la biblioteca que necesita un str, te recomiendo cualquiera de laboriosa búsqueda de los datos anidados estructura después del análisis (que reconozco es lo que explícitamente dijo que quería evitar... lo siento), o tal vez envoltura de sus bibliotecas en algún tipo de fachada donde se puede masaje de los parámetros de entrada en un nivel más granular. El segundo enfoque podría ser más manejable que el primero si tu estructuras de datos son, de hecho, profundamente anidadas.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: