Comment obtenir des objets string au lieu D'Unicode à partir de JSON?

j'utilise Python 2 pour analyser JSON à partir de ASCII encoded fichiers texte.

lors du chargement de ces fichiers avec json ou simplejson , toutes les valeurs de mes chaînes de caractères sont attribuées à des objets Unicode plutôt qu'à des objets string. Le problème est que je dois utiliser les données avec des bibliothèques qui n'acceptent que les objets string. I ne peut pas changer les bibliothèques ni les mettre à jour.

est-il possible d'obtenir des objets string à la place des objets Unicode?

exemple

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

mise à Jour

cette question a été posée il y a longtemps , quand j'étais coincé avec Python 2 . Une solution facile et propre pour aujourd'hui est d'utiliser une version récente de Python - i.e. Python 3 et en avant.

244
demandé sur Brutus 2009-06-05 20:32:17

21 réponses

Une solution object_hook

import json

def json_load_byteified(file_handle):
    return _byteify(
        json.load(file_handle, object_hook=_byteify),
        ignore_dicts=True
    )

def json_loads_byteified(json_text):
    return _byteify(
        json.loads(json_text, object_hook=_byteify),
        ignore_dicts=True
    )

def _byteify(data, ignore_dicts = False):
    # if this is a unicode string, return its string representation
    if isinstance(data, unicode):
        return data.encode('utf-8')
    # if this is a list of values, return list of byteified values
    if isinstance(data, list):
        return [ _byteify(item, ignore_dicts=True) for item in data ]
    # if this is a dictionary, return dictionary of byteified keys and values
    # but only if we haven't already byteified it
    if isinstance(data, dict) and not ignore_dicts:
        return {
            _byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True)
            for key, value in data.iteritems()
        }
    # if it's anything else, return it in its original form
    return data

exemple d'usage:

>>> json_loads_byteified('{"Hello": "World"}')
{'Hello': 'World'}
>>> json_loads_byteified('"I am a top-level string"')
'I am a top-level string'
>>> json_loads_byteified('7')
7
>>> json_loads_byteified('["I am inside a list"]')
['I am inside a list']
>>> json_loads_byteified('[[[[[[[["I am inside a big nest of lists"]]]]]]]]')
[[[[[[[['I am inside a big nest of lists']]]]]]]]
>>> json_loads_byteified('{"foo": "bar", "things": [7, {"qux": "baz", "moo": {"cow": ["milk"]}}]}')
{'things': [7, {'qux': 'baz', 'moo': {'cow': ['milk']}}], 'foo': 'bar'}
>>> json_load_byteified(open('somefile.json'))
{'more json': 'from a file'}

Comment cela fonctionne et pourquoi devrais-je utiliser?

la fonction de Mark Amery est plus courte et plus claire que celles-ci, alors à quoi bon? Pourquoi voudriez-vous utiliser?

Purement performance . La réponse de Mark décode complètement le texte de JSON d'abord avec les chaînes unicode, puis revient à travers toute la valeur décodée pour convertir toutes les chaînes en byte strings. Cela a quelques effets indésirables:

  • une copie de toute la structure décodée est créée en mémoire
  • si votre objet JSON est vraiment profondément imbriqué (500 niveaux ou plus) alors vous atteindrez la profondeur maximale de récursion de Python

cette réponse atténue ces deux problèmes de performance en utilisant le paramètre object_hook de json.load et json.loads . De les docs :

object_hook est une fonction optionnelle qui sera appelée avec le résultat de tout objet littéral décodé (a dict ). La valeur de retour de object_hook sera utilisée à la place du dict . Cette fonctionnalité peut être utilisée pour mettre en œuvre des décodeurs personnalisés

depuis dictionnaires imbriqués à de nombreux niveaux dans d'autres dictionnaires passer à object_hook comme ils sont décodés , nous pouvons byteify toutes les chaînes ou listes à l'intérieur d'eux à ce point et éviter la nécessité de la récursion profonde plus tard.

la réponse de Mark ne peut pas être utilisée comme object_hook telle qu'elle est, parce qu'elle revient dans des dictionnaires imbriqués. Nous empêchons que la récursion dans cette réponse avec le paramètre ignore_dicts à _byteify , qui obtient passé à lui en tout temps sauf quand object_hook lui passe un nouveau dict à byteify. Le drapeau ignore_dicts indique _byteify d'ignorer dict puisqu'ils ont déjà été byteifiés.

enfin, nos implémentations de json_load_byteified et json_loads_byteified appel _byteify (avec ignore_dicts=True ) sur le résultat retourné de json.load ou json.loads pour gérer le cas où le texte JSON étant décodé n'a pas dict au niveau supérieur.

80
répondu Mirec Miskuf 2017-05-23 11:47:14

bien qu'il y ait quelques bonnes réponses ici, j'ai fini par utiliser PyYAML pour analyser mes fichiers JSON, car il donne les clés et les valeurs comme str Type chaînes au lieu de unicode type. Parce que JSON est un sous-ensemble de YAML il fonctionne bien:

>>> 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.safe_load(list_dump)
['a', 'b']

Notes

certaines choses à noter cependant:

  • je reçois objets string parce que tous les mes entrées sont ASCII codé . Si j'utilisais des entrées codées unicode, je les récupérerais en objets unicode - il n'y a pas de conversion!

  • vous devriez (probablement toujours) utiliser la fonction safe_load de PyYAML; si vous l'utilisez pour charger des fichiers JSON, vous n'avez pas besoin de la "puissance supplémentaire" de la fonction load de toute façon.

  • si vous voulez un YAML parser qui a plus de soutien pour la version 1.2 de la spec (et correctement parses très bas nombres ) try Ruamel YAML : pip install ruamel.yaml et import ruamel.yaml as yaml était tout ce dont j'avais besoin dans mes tests.

Conversion

comme indiqué, il n'y a pas de conversion! Si vous ne pouvez pas être sûr de ne traiter que les valeurs ASCII( et vous ne pouvez pas être sûr la plupart du temps), utilisez plutôt une conversion fonction :

j'ai utilisé celle de Marque Amery une couple de fois maintenant, il fonctionne très bien et est très facile à utiliser. Vous pouvez également utiliser une fonction similaire comme un object_hook à la place, car il pourrait vous gagner un boost de performance sur les gros fichiers. Voir la réponse un peu plus impliquée de Mirec Miskuf pour cela.

164
répondu Brutus 2017-05-23 11:54:53

il n'y a pas d'option intégrée pour que les fonctions du module json renvoient des chaînes d'octets au lieu des chaînes unicode. Cependant, cette fonction recursive simple et courte convertira n'importe quel objet JSON décodé en utilisant des chaînes unicode en chaînes Byte encodées en UTF-8:

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

il suffit de l'appeler sur la sortie que vous obtenez à partir d'un appel json.load ou json.loads .

quelques notes:

  • pour supporter Python 2.6 ou plus tôt, remplacer return {byteify(key): byteify(value) for key, value in input.iteritems()} par return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()]) , car les interprétations de dictionnaires n'étaient pas supportées avant Python 2.7.
  • puisque cette réponse revient à travers tout l'objet décodé, elle présente quelques caractéristiques de performance indésirables qui peuvent être évitées en utilisant très soigneusement les paramètres object_hook ou object_pairs_hook . la réponse de Mirec Miskuf est jusqu'à présent la seule qui réussit à tirer cela correctement, bien que comme un la conséquence, c'est beaucoup plus compliqué que mon approche.
137
répondu Mark Amery 2017-05-23 10:31:26

vous pouvez utiliser le paramètre object_hook pour json.loads pour passer dans un convertisseur. Vous n'avez pas à faire la conversion après le fait. Le module json passera toujours les dicts object_hook seulement, et il passera récursivement dans les dicts imbriqués, de sorte que vous n'avez pas à revenir dans les dicts imbriqués vous-même. Je ne pense pas que je convertirais les chaînes unicode en nombres comme Wells montre. Si c'est une chaîne unicode, elle a été citée comme une chaîne de caractères dans le fichier JSON, donc c'est censé être une chaîne de caractères (ou le fichier est mauvais).

aussi, j'essaierais d'éviter de faire quelque chose comme str(val) sur un objet unicode . Vous devez utiliser value.encode(encoding) avec un encodage valide, en fonction de ce que votre lib externe attend.

ainsi, par exemple:

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)
73
répondu Mike Brennan 2014-08-29 17:33:12

c'est parce que json n'a pas de différence entre les objets string et les objets unicode. Ce sont des chaînes en javascript.

je pense JSON est en droit de retour des objets unicode . En fait, je n'accepterais rien de moins, puisque les chaînes javascript sont en fait unicode objets (c.-à-d. JSON (javascript) chaînes peuvent stocker toute sorte de caractère unicode) il est donc logique de créer unicode objets lors de la traduction des chaînes de JSON. Les chaînes simples ne conviennent pas puisque la bibliothèque doit deviner l'encodage que vous voulez.

Il est préférable d'utiliser des unicode chaîne des objets partout. Donc votre meilleure option est de mettre à jour vos bibliothèques pour qu'elles puissent traiter des objets unicode.

mais si vous voulez vraiment bytestrings, il suffit de coder les résultats à l'encodage de votre choix:

>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']
37
répondu nosklo 2009-06-05 18:29:06

Il existe un travail facile.

TL; DR-utiliser ast.literal_eval() au lieu de json.loads() . Les deux ast et json sont dans la bibliothèque standard.

bien que ce ne soit pas une réponse "parfaite", elle va assez loin si votre plan est d'ignorer Unicode tout à fait. En Python 2.7

import json, ast
d = { 'field' : 'value' }
print "JSON Fail: ", json.loads(json.dumps(d))
print "AST Win:", ast.literal_eval(json.dumps(d))

donne:

JSON Fail:  {u'field': u'value'}
AST Win: {'field': 'value'}

cela devient plus difficile quand certains objets sont vraiment des chaînes Unicode. Le la réponse complète devient vite velue.

14
répondu Charles Merriam 2013-11-07 01:01:43

je crains qu'il n'y ait aucun moyen de réaliser cela automatiquement dans la bibliothèque simplejson.

le scanner et le décodeur en simplejson sont conçus pour produire du texte unicode. Pour ce faire, la bibliothèque utilise une fonction appelée c_scanstring (si elle est disponible, pour la vitesse), ou py_scanstring si la version C n'est pas disponible. La fonction scanstring est appelée plusieurs fois par presque chaque routine que simplejson a pour décoder une structure qui pourrait contenir du texte. Vous devez soit surveiller la valeur scanstring dans simplejson.décodeur ,ou sous-classe JSONDecoder et de fournir à peu près votre propre mise en œuvre complète de tout ce qui pourrait contenir du texte.

la raison pour laquelle simplejson produit unicode, cependant, est que le JSON spec mentionne spécifiquement que"une chaîne est une collection de zéro ou plus caractères Unicode"... le support d'unicode est supposé faire partie du format lui-même. Simplejson de l' L'implémentation scanstring va jusqu'à scanner et interpréter les échappées d'unicode (même en vérifiant les erreurs pour les représentations de charset multi-octets mal formées), de sorte que la seule façon fiable de vous retourner la valeur est en unicode.

si vous avez une vieille bibliothèque qui a besoin d'un str , je vous recommande soit laborieusement rechercher la structure de données imbriquée après analyse (ce que je reconnais est ce que vous avez explicitement dit que vous vouliez éviter... désolé), ou peut-être envelopper votre bibliothèques dans une sorte de façade où vous pouvez masser les paramètres d'entrée à un niveau plus granulaire. La deuxième approche pourrait être plus facile à gérer que la première si vos structures de données sont en effet profondément imbriquées.

9
répondu Jarret Hardie 2009-06-05 18:10:03

la réponse de Mike Brennan est proche, mais il n'y a aucune raison de traverser à nouveau toute la structure. Si vous utilisez object_hook_pairs (Python 2.7+) paramètre:

object_pairs_hook est une fonction optionnelle qui sera appelée avec le résultat de n'importe quel objet littéral décodé avec une liste ordonnée de paires. La valeur de retour de object_pairs_hook sera utilisé à la place du dict . Cette fonctionnalité peut être utilisée pour implémenter des décodeurs qui reposent sur l'ordre que les paires clé-valeur sont décodés (par exemple, collections.OrderedDict se souviendra de l'ordre d'insertion). Si object_hook est également défini, le object_pairs_hook a priorité.

avec elle, vous obtenez chaque objet JSON remis à vous, de sorte que vous pouvez faire le décodage sans besoin de recursion:

def deunicodify_hook(pairs):
    new_pairs = []
    for key, value in pairs:
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        if isinstance(key, unicode):
            key = key.encode('utf-8')
        new_pairs.append((key, value))
    return dict(new_pairs)

In [52]: open('test.json').read()
Out[52]: '{"1": "hello", "abc": [1, 2, 3], "def": {"hi": "mom"}, "boo": [1, "hi", "moo", {"5": "some"}]}'                                        

In [53]: json.load(open('test.json'))
Out[53]: 
{u'1': u'hello',
 u'abc': [1, 2, 3],
 u'boo': [1, u'hi', u'moo', {u'5': u'some'}],
 u'def': {u'hi': u'mom'}}

In [54]: json.load(open('test.json'), object_pairs_hook=deunicodify_hook)
Out[54]: 
{'1': 'hello',
 'abc': [1, 2, 3],
 'boo': [1, 'hi', 'moo', {'5': 'some'}],
 'def': {'hi': 'mom'}}

notez que je n'ai jamais à appeler le crochet récursivement puisque chaque objet sera remis au crochet lorsque vous utilisez le object_pairs_hook . Vous devez vous soucier des listes, mais comme vous pouvez le voir, un objet à l'intérieur d'une liste sera correctement converti, et vous n'avez pas à recommencer pour le faire se produire.

EDIT: un collaborateur a souligné que Python2.6 n'a pas object_hook_pairs . Vous pouvez toujours utiliser ce sera Python2.6 en faisant un très petit changement. Dans le crochet ci-dessus, changer:

for key, value in pairs:

à

for key, value in pairs.iteritems():

puis utiliser object_hook au lieu de object_pairs_hook :

In [66]: json.load(open('test.json'), object_hook=deunicodify_hook)
Out[66]: 
{'1': 'hello',
 'abc': [1, 2, 3],
 'boo': [1, 'hi', 'moo', {'5': 'some'}],
 'def': {'hi': 'mom'}}

L'utilisation de object_pairs_hook résulte en un dictionnaire de moins étant instancié pour chaque objet dans l'objet JSON, qui, si vous parsiez un document énorme, pourrait être utile pendant.

9
répondu Travis Jensen 2017-05-23 12:34:33

comme marque (Amery) note correctement: L'utilisation de PyYaml 's deserializer sur un dump JSON ne fonctionne que si vous avez ASCII seulement. Au moins hors de la boîte.

deux rapides commentaires sur L'approche PyYaml:

  1. jamais utilisez yaml.charge sur les données du champ. Sa fonctionnalité(!) de yaml pour exécuter du code arbitraire caché dans la structure.

  2. Vous peut faire fonctionner aussi pour les non ASCII via ceci:

    def to_utf8(loader, node):
        return loader.construct_scalar(node).encode('utf-8')
    yaml.add_constructor(u'tag:yaml.org,2002:str', to_utf8)
    

mais la performance sage De aucune comparaison à la réponse de Mark Amery:

jetant quelques dicts échantillons profondément emboîtés sur les deux méthodes, j'obtiens ceci (avec dt[j] = delta de temps de JSON.charges(json.dumps (m)):

     dt[yaml.safe_load(json.dumps(m))] =~ 100 * dt[j]
     dt[byteify recursion(Mark Amery)] =~   5 * dt[j]

ainsi désérialisation y compris la marche complète de l'arbre et Encodage , bien dans l'ordre de grandeur de l'implémentation basée sur le C. Je trouve cela remarquablement rapide et son aussi plus robuste que la charge yaml à des structures profondément imbriquées. Et moins d'erreurs de sécurité, en regardant yaml.charge.

= > alors que j'apprécierais un pointeur vers un convertisseur C uniquement basé la fonction byteify devrait être la réponse par défaut.

Cela est particulièrement vrai si votre structure json est depuis le champ, contenant les entrées de l'utilisateur. Parce qu'alors vous avez probablement besoin de marcher de toute façon sur votre structure - indépendant sur vos structures de données internes désirées ("sandwich unicode" ou chaînes byte seulement).

pourquoi?

Unicode normalisation "de la 151940920" . Pour les non-avertis: prendre un analgésique et lire ce .

donc en utilisant la recursion de byteify vous tuez deux oiseaux avec une pierre:

  1. obtenir votre bytestrings de imbriquée json décharges
  2. normalisez les valeurs d'entrée de l'utilisateur, pour que vous trouviez le contenu de votre stockage.

Dans mes tests, il s'est avéré que le remplacement de l'entrée.encoder ('utf-8') avec une unicodedata.normaliser ('NFC', input).encode ('utf-8') était encore plus rapide que w/o NFC - mais cela dépend fortement des données de l'échantillon je suppose.

4
répondu Red Pill 2015-04-14 17:42:03

le gotcha est que simplejson et json sont deux modules différents, au moins dans la façon dont ils traitent unicode. Vous avez json dans py 2.6+, et cela vous donne des valeurs unicode, alors que simplejson renvoie des objets string. Il suffit d'essayer easy_install-ing simplejson dans votre environnement et de voir si cela fonctionne. Il l'a fait pour moi.

3
répondu ducu 2010-10-19 19:48:34

donc, j'ai rencontré le même problème. Devinez quel a été le premier résultat de Google.

parce que J'ai besoin de passer toutes les données à PyGTK, les chaînes unicode ne sont pas très utiles pour moi non plus. J'ai donc une autre méthode de conversion récursive. Il est en fait également nécessaire pour la conversion de typesafe JSON - json.dump () sauterait sur tous les objets non-littéraux, comme les objets Python. Mais il ne convertit pas les index de dict.

# removes any objects, turns unicode back into str
def filter_data(obj):
        if type(obj) in (int, float, str, bool):
                return obj
        elif type(obj) == unicode:
                return str(obj)
        elif type(obj) in (list, tuple, set):
                obj = list(obj)
                for i,v in enumerate(obj):
                        obj[i] = filter_data(v)
        elif type(obj) == dict:
                for i,v in obj.iteritems():
                        obj[i] = filter_data(v)
        else:
                print "invalid object in data, converting to string"
                obj = str(obj) 
        return obj
1
répondu mario 2010-07-05 18:22:51

il suffit d'utiliser pickle à la place de json pour dump et load, comme ainsi:

    import json
    import pickle

    d = { 'field1': 'value1', 'field2': 2, }

    json.dump(d,open("testjson.txt","w"))

    print json.load(open("testjson.txt","r"))

    pickle.dump(d,open("testpickle.txt","w"))

    print pickle.load(open("testpickle.txt","r"))

la sortie qu'il produit est (les chaînes et les entiers sont manipulés correctement):

    {u'field2': 2, u'field1': u'value1'}
    {'field2': 2, 'field1': 'value1'}
1
répondu Stefan Gruenwald 2014-04-27 20:15:01

supporte Python2 & 3 en utilisant hook (à partir de https://stackoverflow.com/a/33571117/558397 )

import requests
import six
from six import iteritems

requests.packages.urllib3.disable_warnings()  # @UndefinedVariable
r = requests.get("http://echo.jsontest.com/key/value/one/two/three", verify=False)

def _byteify(data):
    # if this is a unicode string, return its string representation
    if isinstance(data, six.string_types):
        return str(data.encode('utf-8').decode())

    # if this is a list of values, return list of byteified values
    if isinstance(data, list):
        return [ _byteify(item) for item in data ]

    # if this is a dictionary, return dictionary of byteified keys and values
    # but only if we haven't already byteified it
    if isinstance(data, dict):
        return {
            _byteify(key): _byteify(value) for key, value in iteritems(data)
        }
    # if it's anything else, return it in its original form
    return data

w = r.json(object_hook=_byteify)
print(w)

Retourne:

 {'three': '', 'key': 'value', 'one': 'two'}
1
répondu abarik 2017-08-21 20:16:47

c'est tard pour le jeu, mais j'ai construit ce jeteur récursif. Il répond à mes besoins et je pense qu'il est relativement complet. Il peut vous aider.

def _parseJSON(self, obj):
    newobj = {}

    for key, value in obj.iteritems():
        key = str(key)

        if isinstance(value, dict):
            newobj[key] = self._parseJSON(value)
        elif isinstance(value, list):
            if key not in newobj:
                newobj[key] = []
                for i in value:
                    newobj[key].append(self._parseJSON(i))
        elif isinstance(value, unicode):
            val = str(value)
            if val.isdigit():
                val = int(val)
            else:
                try:
                    val = float(val)
                except ValueError:
                    val = str(val)
            newobj[key] = val

    return newobj

passez-lui un objet JSON comme ceci:

obj = json.loads(content, parse_float=float, parse_int=int)
obj = _parseJSON(obj)

je l'ai comme un membre privé d'une classe, mais vous pouvez réutiliser la méthode que vous voyez l'ajustement.

0
répondu Wells 2009-10-29 03:53:43

j'ai réécrit _parse_json() de Wells pour gérer les cas où l'objet json lui-même est un tableau (mon cas d'utilisation).

def _parseJSON(self, obj):
    if isinstance(obj, dict):
        newobj = {}
        for key, value in obj.iteritems():
            key = str(key)
            newobj[key] = self._parseJSON(value)
    elif isinstance(obj, list):
        newobj = []
        for value in obj:
            newobj.append(self._parseJSON(value))
    elif isinstance(obj, unicode):
        newobj = str(obj)
    else:
        newobj = obj
    return newobj
0
répondu darnmarshall 2013-06-07 05:12:22

voici un encodeur récursif écrit en C: https://github.com/axiros/nested_encode

surcharge de Performance pour la "moyenne" des structures autour de 10% par rapport à json.charge.

python speed.py                                                                                            
  json loads            [0.16sec]: {u'a': [{u'b': [[1, 2, [u'\xd6ster..
  json loads + encoding [0.18sec]: {'a': [{'b': [[1, 2, ['\xc3\x96ster.
  time overhead in percent: 9%

utilisant cette structure d'essai:

import json, nested_encode, time

s = """
{
  "firstName": "Jos\u0301",
  "lastName": "Smith",
  "isAlive": true,
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "\u00d6sterreich",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null,
  "a": [{"b": [[1, 2, ["\u00d6sterreich"]]]}]
}
"""


t1 = time.time()
for i in xrange(10000):
    u = json.loads(s)
dt_json = time.time() - t1

t1 = time.time()
for i in xrange(10000):
    b = nested_encode.encode_nested(json.loads(s))
dt_json_enc = time.time() - t1

print "json loads            [%.2fsec]: %s..." % (dt_json, str(u)[:20])
print "json loads + encoding [%.2fsec]: %s..." % (dt_json_enc, str(b)[:20])

print "time overhead in percent: %i%%"  % (100 * (dt_json_enc - dt_json)/dt_json)
0
répondu Red Pill 2015-05-04 12:44:46

j'ai eu un JSON dict comme corde. Les clés et les valeurs étaient des objets unicode comme dans l'exemple suivant:

myStringDict = "{u'key':u'value'}"

je pourrais utiliser la fonction byteify suggérée ci-dessus en convertissant la chaîne de caractères en un objet dict en utilisant ast.literal_eval(myStringDict) .

0
répondu narko 2016-11-17 15:17:21

Check out ce réponse à une question similaire, comme ce qui stipule que

le préfixe u signifie simplement que vous avez une chaîne Unicode. Lorsque vous utilisez la chaîne, il n'apparaîtra pas dans vos données. Ne vous laissez pas jeter par la sortie imprimée.

par exemple, essayez ceci:

print mail_accounts[0]["i"]

vous ne verrez pas un U.

0
répondu kunal 2017-07-04 13:32:45

avec Python 3.6, parfois je rencontre encore ce problème. Par exemple, lorsque j'obtiens la réponse d'une API REST et que je charge le texte de réponse à JSON, j'obtiens toujours les chaînes unicode. J'ai trouvé une solution simple en utilisant json.dumps.)(

response_message = json.loads(json.dumps(response.text))
print(response_message)
0
répondu Yuelin 2018-04-25 17:17:55

j'ai rencontré ce problème aussi, et en ayant affaire à JSON, j'ai créé une petite boucle qui convertit les clés unicode en chaînes. ( simplejson sur GAE ne renvoie pas les clés de chaîne.)

obj est l'objet décodé de JSON:

if NAME_CLASS_MAP.has_key(cls):
    kwargs = {}
    for i in obj.keys():
        kwargs[str(i)] = obj[i]
    o = NAME_CLASS_MAP[cls](**kwargs)
    o.save()

kwargs est ce que je passe au constructeur de L'application GAE (qui n'aime pas unicode clés dans **kwargs )

pas aussi robuste que la solution de Wells, mais beaucoup plus petit.

-1
répondu boatcoder 2014-08-29 17:01:18

j'ai adapté le code de la réponse de Mark Amery , en particulier afin de se débarrasser de isinstance pour les pros de canard-typing.

le codage se fait manuellement et ensure_ascii est désactivé. Le python docs pour json.dump dit que

si ensure_ascii est True( par défaut), tous les caractères non-ASCII de la sortie sont echappé avec des séquences \uXXXX

Avertissement: dans le doctest j'ai utilisé la langue hongroise. Parmi les encodages de caractères liés à la Hongrie, on peut citer: cp852 l'encodage IBM/OEM utilisé par ex. dans DOS (parfois dénommé ascii , à tort je pense, il dépend de la codepage ), cp1250 utilisé par exemple. dans Windows (parfois appelé ansi , dépendant de la paramètres régionaux), et iso-8859-2 , parfois utilisé sur les serveurs http. Le texte d'essai Tüskéshátú kígyóbűvölő est attribué à Koltai László (forme de nom personnel natif) et est de wikipedia .

# coding: utf-8
"""
This file should be encoded correctly with utf-8.
"""
import json

def encode_items(input, encoding='utf-8'):
    u"""original from: https://stackoverflow.com/a/13101776/611007
    adapted by SO/u/611007 (20150623)
    >>> 
    >>> ## run this with `python -m doctest <this file>.py` from command line
    >>> 
    >>> txt = u"Tüskéshátú kígyóbűvölő"
    >>> txt2 = u"T\u00fcsk\u00e9sh\u00e1t\u00fa k\u00edgy\u00f3b\u0171v\u00f6l\u0151"
    >>> txt3 = u"uúuutifu"
    >>> txt4 = b'u\xfauutifu'
    >>> # txt4 shouldn't be 'u\xc3\xbauutifu', string content needs double backslash for doctest:
    >>> assert u'\u0102' not in b'u\xfauutifu'.decode('cp1250')
    >>> txt4u = txt4.decode('cp1250')
    >>> assert txt4u == u'u\xfauutifu', repr(txt4u)
    >>> txt5 = b"u\xc3\xbauutifu"
    >>> txt5u = txt5.decode('utf-8')
    >>> txt6 = u"u\u251c\u2551uutifu"
    >>> there_and_back_again = lambda t: encode_items(t, encoding='utf-8').decode('utf-8')
    >>> assert txt == there_and_back_again(txt)
    >>> assert txt == there_and_back_again(txt2)
    >>> assert txt3 == there_and_back_again(txt3)
    >>> assert txt3.encode('cp852') == there_and_back_again(txt4u).encode('cp852')
    >>> assert txt3 == txt4u,(txt3,txt4u)
    >>> assert txt3 == there_and_back_again(txt5)
    >>> assert txt3 == there_and_back_again(txt5u)
    >>> assert txt3 == there_and_back_again(txt4u)
    >>> assert txt3.encode('cp1250') == encode_items(txt4, encoding='utf-8')
    >>> assert txt3.encode('utf-8') == encode_items(txt5, encoding='utf-8')
    >>> assert txt2.encode('utf-8') == encode_items(txt, encoding='utf-8')
    >>> assert {'a':txt2.encode('utf-8')} == encode_items({'a':txt}, encoding='utf-8')
    >>> assert [txt2.encode('utf-8')] == encode_items([txt], encoding='utf-8')
    >>> assert [[txt2.encode('utf-8')]] == encode_items([[txt]], encoding='utf-8')
    >>> assert [{'a':txt2.encode('utf-8')}] == encode_items([{'a':txt}], encoding='utf-8')
    >>> assert {'b':{'a':txt2.encode('utf-8')}} == encode_items({'b':{'a':txt}}, encoding='utf-8')
    """
    try:
        input.iteritems
        return {encode_items(k): encode_items(v) for (k,v) in input.iteritems()}
    except AttributeError:
        if isinstance(input, unicode):
            return input.encode(encoding)
        elif isinstance(input, str):
            return input
        try:
            iter(input)
            return [encode_items(e) for e in input]
        except TypeError:
            return input

def alt_dumps(obj, **kwargs):
    """
    >>> alt_dumps({'a': u"T\u00fcsk\u00e9sh\u00e1t\u00fa k\u00edgy\u00f3b\u0171v\u00f6l\u0151"})
    '{"a": "T\xc3\xbcsk\xc3\xa9sh\xc3\xa1t\xc3\xba k\xc3\xadgy\xc3\xb3b\xc5\xb1v\xc3\xb6l\xc5\x91"}'
    """
    if 'ensure_ascii' in kwargs:
        del kwargs['ensure_ascii']
    return json.dumps(encode_items(obj), ensure_ascii=False, **kwargs)

je voudrais aussi souligner la réponse de jarret Hardie qui fait référence à la JSON spec , citant:

une chaîne est une collection de zéro ou plus caractères Unicode

dans mon étui j'avais des fichiers avec json. Ce sont des fichiers codés utf-8 . ensure_ascii se traduit par des fichiers JSON correctement échappés mais pas très lisibles, c'est pourquoi J'ai adapté la réponse de Mark Amery à mes besoins.

La doctest n'est pas particulièrement attentionné, mais je partage le code dans l'espoir qu'il sera utile pour quelqu'un.

-1
répondu n611x007 2015-11-03 07:59:46