首页 文章

如何从JSON获取字符串对象而不是Unicode?

提问于
浏览
247

我正在使用 Python 2 来解析 ASCII encoded 文本文件中的JSON .

使用jsonsimplejson加载这些文件时,我的所有字符串值都将转换为Unicode对象而不是字符串对象 . 问题是,我必须将数据用于一些只接受字符串对象的库 . 我不能更改库也不能更新它们 .

是否可以获取字符串对象而不是Unicode对象?

示例

>>> 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`

更新

很久以前,当我被困 Python 2 时,这个问题被问到了 . 今天一个简单而干净的解决方案是使用最新版本的Python - 即 Python 3 和转发 .

21 回答

  • 85

    我有一个JSON字典作为字符串 . 键和值是unicode对象,如下例所示:

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

    我可以通过使用 ast.literal_eval(myStringDict) 将字符串转换为 dict 对象来使用上面建议的 byteify 函数 .

  • 37

    查看this对类似问题的回答,其中说明了这一点

    u-前缀只表示您有一个Unicode字符串 . 当您真正使用该字符串时,它不会出现在您的数据中 . 不要被打印输出抛出 .

    例如,试试这个:

    print mail_accounts[0]["i"]
    

    你不会看到你 .

  • 164

    使用hook支持Python2和3(来自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)
    

    返回:

    {'three': '', 'key': 'value', 'one': 'two'}
    
  • 138

    只需使用pickle代替json进行转储和加载,如下所示:

    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"))
    

    它产生的输出是(正确处理字符串和整数):

    {u'field2': 2, u'field1': u'value1'}
        {'field2': 2, 'field1': 'value1'}
    
  • 9

    您可以使用json.loadsobject_hook 参数传入转换器 . 事后你不必进行转换 . json模块将始终仅传递 object_hook dicts,并且它将以递归方式传递嵌套的dicts,因此您不会认为我会将unicode字符串转换为Wells节目等数字 . 如果它是一个unicode字符串,它在JSON文件中被引用为一个字符串,所以它应该是一个字符串(或文件是坏的) .

    另外,我会尽量避免在 unicode 对象上做 str(val) 之类的事情 . 您应该将 value.encode(encoding) 与有效编码一起使用,具体取决于外部lib期望的内容 .

    所以,例如:

    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)
    
  • 0

    使用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
    

    用法示例:

    >>> 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'}
    

    这是如何工作的,为什么我会使用它?

    Mark Amery's function比这些更短更清晰,那么它们有什么意义呢?你为什么要用它们?

    纯粹为 performance . Mark的回答首先使用unicode字符串完全解码JSON文本,然后通过整个解码值进行递归,将所有字符串转换为字节字符串 . 这有几个不良影响:

    • 整个解码结构的副本在内存中创建

    • 如果您的JSON对象真的是嵌套的(500级或更多),那么'll hit Python'的最大递归深度

    此答案通过使用 json.loadjson.loadsobject_hook 参数来缓解这两个性能问题 . 来自the docs

    object_hook是一个可选函数,将使用任何对象文字解码(dict)的结果调用 . 将使用object_hook的返回值而不是dict . 此功能可用于实现自定义解码器

    由于字典在其他字典中嵌套了许多级别,因此在它们被解码时会被传递给 object_hook ,我们可以在那时对其中的任何字符串或列表进行字节化,并避免以后需要进行深度递归 .

    Mark 's answer isn' t适合用作 object_hook ,因为它可以递归到嵌套的词典中 . 我们使用 ignore_dicts 参数来阻止该答案中的递归到 _byteify ,除非 object_hook 将新的 dict 传递给byteify,否则它会一直传递给它 . ignore_dicts 标志告诉 _byteify 忽略 dict ,因为它们已被字节化 .

    最后,我们的 json_load_byteifiedjson_loads_byteified 的实现对从 json.loadjson.loads 返回的结果调用 _byteify (带 ignore_dicts=True ),以处理被解码的JSON文本在顶层没有 dict 的情况 .

  • 0

    没有内置选项使json模块函数返回字节字符串而不是unicode字符串 . 但是,这个简短而简单的递归函数会将任何已解码的JSON对象从使用unicode字符串转换为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
    

    只需在 json.loadjson.loads 调用的输出上调用它 .

    几个笔记:

    • 为了支持Python 2.6或更早版本,请将 return {byteify(key): byteify(value) for key, value in input.iteritems()} 替换为 return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()]) ,因为在Python 2.7之前不支持字典理解 .

    • 由于此答案通过整个解码对象进行递归,因此它具有一些不良的性能特征,可以通过非常小心地使用 object_hookobject_pairs_hook 参数来避免这些特性 . Mirec Miskuf's answer是迄今为止唯一能够正确解决这个问题的人,尽管如此,它比我的方法复杂得多 .

  • 15

    那是因为json在字符串对象和unicode对象之间没有区别 . 它们都是javascript中的所有字符串 .

    我想 JSON is right to return unicode objects . 事实上,我不会接受任何更少,因为javascript字符串 are in fact unicode objects (即JSON(javascript)字符串可以存储任何类型的unicode字符)所以在翻译时创建 unicode 对象是有意义的来自JSON的字符串 . 简单的字符串是不适合的,因为库必须猜测你想要的编码 .

    最好在任何地方使用 unicode 字符串对象 . 因此,您最好的选择是更新库,以便它们可以处理unicode对象 .

    但是如果你真的想要字节串,只需将结果编码为你选择的编码:

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

    所以,我遇到了同样的问题 . 猜猜Google的第一个结果是什么 .

    因为我需要将所有数据传递给PyGTK,所以unicode字符串对我来说也不是很有用 . 所以我有另一种递归转换方法 . 它实际上也需要类型安全的JSON转换 - json.dump()会保留任何非文字,比如Python对象 . 虽然不转换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

    有一个简单的解决方法 .

    TL; DR - 使用 ast.literal_eval() 而不是 json.loads() . astjson 都在标准库中 .

    虽然不是一个“完美”的答案,如果您的计划完全忽略Unicode,它会得到一个很好的答案 . 在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))
    

    得到:

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

    当某些对象真的是Unicode字符串时,这会变得更加毛茸茸 . 完整的答案会很快变得毛茸茸 .

  • 73

    正如Mark(Amery)正确指出的那样:在json转储上使用 PyYaml 的反序列化器只有在你只有ASCII时才有效 . 至少开箱即用 .

    关于PyYaml方法的两个快速评论:

    • NEVER对字段中的数据使用yaml.load . 它是yaml的一个特性(!),用于执行隐藏在结构中的任意代码 .

    • 您可以通过以下方式使其适用于非ASCII:

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

    但表现明智,它与马克·阿梅里的回答无可比拟:

    把一些深层嵌套的样本dicts扔到两个方法上,我得到了这个(用dt [j] = json.loads的时间增量(json.dumps(m))):

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

    因此反序列化包括完全遍历树和编码,完全在json的基于C的实现的数量级内 . 我发现它非常快,并且它比深嵌套结构中的yaml负载更强大 . 并且更少安全性容易出错,看着yaml.load .

    =>虽然我很欣赏指向基于C的转换器的指针,但 byteify function 应该是默认答案 .

    如果您的json结构来自包含用户输入的字段,则尤其如此 . 因为那时您可能需要在结构上行走 - 独立于您期望的内部数据结构(仅限'unicode sandwich'或字节字符串) .

    为什么?

    Unicode normalisation . 不知不觉:服用止痛药并阅读this .

    因此,使用byteify递归可以一举两得:

    • 从嵌套的json转储中获取您的字节串

    • 获取规范化的用户输入值,以便您在存储中找到内容 .

    在我的测试中,结果发现用unicodedata.normalize('NFC',输入).encode('utf-8')替换input.encode('utf-8')比没有NFC更快 - 但是那我很大程度上依赖于样本数据 .

  • -1

    这是一个用C编写的递归编码器:https://github.com/axiros/nested_encode

    与json.load相比,“平均”结构的性能开销约为10% .

    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%
    

    使用此测试结构:

    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

    Mike Brennan's answer已关闭,但没有理由重新遍历整个结构 . 如果您使用object_hook_pairs(Python 2.7)参数:

    object_pairs_hook是一个可选函数,将使用有序的对列表对解码的任何对象文字的结果进行调用 . 将使用object_pairs_hook的返回值而不是dict . 此功能可用于实现依赖于键和值对被解码的顺序的自定义解码器(例如,collections.OrderedDict将记住插入的顺序) . 如果还定义了object_hook,则object_pairs_hook优先 .

    有了它,您可以获得每个JSON对象,因此您可以在不需要递归的情况下进行解码:

    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'}}
    

    请注意,我永远不必递归地调用钩子,因为当你使用 object_pairs_hook 时,每个对象都会被传递给钩子 . 您必须关心列表,但正如您所看到的,列表中的对象将被正确转换,您无需递归即可实现 .

    编辑:一位同事指出Python2.6没有 object_hook_pairs . 您仍然可以通过进行非常小的更改来使用Python2.6 . 在上面的钩子中,改变:

    for key, value in pairs:
    

    for key, value in pairs.iteritems():
    

    然后使用 object_hook 而不是 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'}}
    

    使用 object_pairs_hook 导致为JSON对象中的每个对象实例化一个较少的字典,如果您正在解析一个巨大的文档,那么可能值得 .

  • 0

    我担心在simplejson库中无法自动实现这一点 .

    simplejson中的扫描仪和解码器是旨在生成unicode文本 . 为此,库使用名为 c_scanstring 的函数(如果可用,速度为),如果C版本不可用,则使用 py_scanstring . 几乎所有simplejson用于解码可能包含文本的结构的例程都会多次调用 scanstring 函数 . 您必须在simplejson.decoder中对 scanstring 值进行monkeypatch,或者子类 JSONDecoder 并提供几乎所有可能包含文本的实现 .

    然而,simplejson输出unicode的原因是json spec特别提到"A string is a collection of zero or more Unicode characters" ...对unicode的支持被假定为格式本身的一部分 . Simplejson的 scanstring 实现甚至扫描和解释unicode转义(甚至错误检查格式错误的多字节字符集表示),因此它可以可靠地将值返回给你的唯一方法是unicode .

    如果您有一个需要 str 的老化库,我建议您在解析后仔细搜索嵌套数据结构(我承认您明确表示要避免...抱歉),或者可能将您的库包装在某种类型中在门面,您可以在更细粒度的水平按摩输入参数 . 如果您的数据结构确实是嵌套的,那么第二种方法可能比第一种方法更易于管理 .

  • 1

    问题是 simplejsonjson 是两个不同的模块,至少以它们处理unicode的方式 . 你在py 2.6中有 json ,这给你unicode值,而 simplejson 返回字符串对象 . 只需在您的环境中尝试easy_install-ing simplejson,看看是否有效 . 它对我有用 .

  • 3

    我也遇到了这个问题,并且不得不处理JSON,我想出了一个将unicode键转换为字符串的小循环 . (GAE上的 simplejson 不返回字符串键 . )

    obj 是从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 是我传递给GAE应用程序的构造函数(它不喜欢 **kwargs 中的 unicode 键)

    不像Wells的解决方案那么强大,但要小得多 .

  • 4

    虽然这里有一些很好的答案,但我最终使用PyYAML来解析我的JSON文件,因为它将键和值作为 str 类型字符串而不是 unicode 类型 . 因为JSON是YAML的一个子集,所以它可以很好地工作:

    >>> 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']
    

    注意事项

    有些事情需要注意:

    • 我得到了字符串对象,因为我的所有条目都是 ASCII encoded . 如果我使用unicode编码的条目,我会把它们作为unicode对象取回 - 没有转换!

    • 你应该(可能总是)使用PyYAML的 safe_load 函数;如果您使用它来加载JSON文件,则无论如何都不需要 load 函数的"additional power" .

    • 如果你想要一个对规范的1.2版本有更多支持的YAML解析器(和correctly parses very low numbers),请尝试Ruamel YAMLpip install ruamel.yamlimport ruamel.yaml as yaml ,这是我在测试中所需要的 .

    转换

    如上所述,没有转换!如果你可以确保大多数时间,请更好地使用 conversion function

    我现在使用了Mark Amery中的那个,它很好用并且非常容易使用 . 您也可以使用与 object_hook 类似的功能,因为它可能会使您在大文件上获得性能提升 . 请参阅稍微复杂一点的answer from Mirec Miskuf .

  • 0

    我已经改编了answeranswer中的代码,特别是为了摆脱 isinstance 为鸭子打字的优点 .

    编码手动完成,并禁用 ensure_ascii . json.dump的python文档说明了这一点

    如果ensure_ascii为True(默认值),则输出中的所有非ASCII字符都将使用\ uXXXX序列进行转义

    免责声明:在doctest中我使用匈牙利语 . 一些值得注意的与匈牙利相关的字符编码是: cp852 使用的IBM / OEM编码 . 在DOS中(有时称为ascii,我认为不正确,它取决于代码页设置),例如 cp1250 . 在Windows中(有时称为ansi,取决于区域设置)和 iso-8859-2 ,有时在http服务器上使用 . 测试文本 Tüskéshátú kígyóbűvölő 归功于KoltaiLászló(本地个人姓名表),来自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)
    

    我还要强调引用JSON specJarret Hardieanswer,引用:

    字符串是零个或多个Unicode字符的集合

    在我的用例中,我有json的文件 . 它们是 utf-8 编码的文件 . ensure_ascii 导致正确转义但不易读取的json文件,这就是为什么我能够满足我的需求 .

    doctest不是特别贴心,但我分享了代码,希望它对某人有用 .

  • 1

    这是游戏的后期,但我建造了这个递归的施法者 . 它适用于我的需求,我认为它相对完整 . 它可能会帮助你 .

    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
    

    只需传递一个JSON对象,如下所示:

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

    我把它作为一个类的私有成员,但你可以重新调整方法,如你所见适合 .

  • -1

    我重写了Wells的_parse_json()来处理json对象本身是一个数组的情况(我的用例) .

    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
    
  • 9

    使用Python 3.6,有时我仍会遇到这个问题 . 例如,当从REST API获取响应并将响应文本加载到JSON时,我仍然获得unicode字符串 . 使用json.dumps()找到了一个简单的解决方案 .

    response_message = json.loads(json.dumps(response.text))
    print(response_message)
    

相关问题