如何使用json.loads将string int JSON转换为real int

时间:2017-07-12 22:58:47

标签: python json python-2.7 parsing

我正在尝试使用json.loads将表示JSON对象的字符串转换为真正的JSON对象,但它不会转换整数:

(在初始字符串中,整数总是字符串)

$> python
Python 2.7.9 (default, Aug 29 2016, 16:00:38)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> c = '{"value": "42"}'
>>> json_object = json.loads(c, parse_int=int)
>>> json_object
{u'value': u'42'}
>>> json_object['value']
u'42'
>>>

而不是{u'value': u'42'}我希望它成为{u'value': 42}。我知道我可以遍历整个对象,但是我不想这样做,手动执行它并不是很有效,因为存在parse_int参数https://docs.python.org/2/library/json.html#json.loads)。

感谢皮尔斯的主张:

Python 2.7.9 (default, Aug 29 2016, 16:00:38)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>>
>>> class Decoder(json.JSONDecoder):
...     def decode(self, s):
...         result = super(Decoder, self).decode(s)
...         return self._decode(result)
...     def _decode(self, o):
...         if isinstance(o, str) or isinstance(o, unicode):
...             try:
...                 return int(o)
...             except ValueError:
...                 try:
...                     return float(o)
...                 except ValueError:
...                     return o
...         elif isinstance(o, dict):
...             return {k: self._decode(v) for k, v in o.items()}
...         elif isinstance(o, list):
...             return [self._decode(v) for v in o]
...         else:
...             return o
...
>>>
>>> c = '{"value": "42", "test": "lolol", "abc": "43.4",  "dcf": 12, "xdf": 12.4}'
>>> json.loads(c, cls=Decoder)
{u'test': u'lolol', u'dcf': 12, u'abc': 43.4, u'value': 42, u'xdf': 12.4}

4 个答案:

答案 0 :(得分:6)

正如我们在评论中所确定的那样,没有现成的功能可以帮助您。我阅读了JSONDecoder上的文档和一些示例,如果不对数据进行两次处理,它似乎也没有做到你想做的事情。

最好的选择就是这样:

class Decoder(json.JSONDecoder):
    def decode(self, s):
        result = super().decode(s)  # result = super(Decoder, self).decode(s) for Python 2.x
        return self._decode(result)

    def _decode(self, o):
        if isinstance(o, str) or isinstance(o, unicode):
            try:
                return int(o)
            except ValueError:
                return o
        elif isinstance(o, dict):
            return {k: self._decode(v) for k, v in o.items()}
        elif isinstance(o, list):
            return [self._decode(v) for v in o]
        else:
            return o

这有两次处理JSON对象的缺点 - 一次在super().decode(s)调用中,并再次通过整个结构来解决问题。另请注意,会将看似整数的任何内容转换为int 。请务必妥善解决此问题。

要使用它,你可以这样做:

>>> c = '{"value": "42"}'
>>> json.loads(c, cls=Decoder)
{'value': 42}

答案 1 :(得分:3)

除了Pierce响应之外,我认为您可以使用json.loads object_hook参数而不是cls参数,因此您不需要两次遍历json对象。

例如:

def _decode(o):
    # Note the "unicode" part is only for python2
    if isinstance(o, str) or isinstance(o, unicode):
        try:
            return int(o)
        except ValueError:
            return o
    elif isinstance(o, dict):
        return {k: _decode(v) for k, v in o.items()}
    elif isinstance(o, list):
        return [_decode(v) for v in o]
    else:
        return o

# Then you can do:
json.loads(c, object_hook=_decode)

正如@ZhanwenChen在评论中指出的那样,上面的代码是python2。对于python3,您需要删除第一个or isinstance(o, unicode)条件中的if部分。

答案 2 :(得分:0)

这是我的解决方案!我使用了object_hook,当您嵌套json

时非常有用
>>> import json
>>> json_data = '{"1": "one", "2": {"-3": "minus three", "4": "four"}}'
>>> py_dict = json.loads(json_data, object_hook=lambda d: {int(k) if k.lstrip('-').isdigit() else k: v for k, v in d.items()})

>>> py_dict
{1: 'one', 2: {-3: 'minus three', 4: 'four'}}

只有过滤器用于将json键解析为int。您也可以将int(v) if v.lstrip('-').isdigit() else v过滤器用于json值。

答案 3 :(得分:-3)

def convert_to_int(params):
    for key in params.keys():
        if isinstance(params[key], dict):
            convert_to_int(params[key])
        elif isinstance(params[key], list):
            for item in params[key]:
                if not isinstance(item, (dict, list)):
                    item = int(item)
                else:
                    convert_to_int(item)
        else:
            params[key] = int(params[key])
    return params


print convert_to_int({'a': '3', 'b': {'c': '4', 'd': {'e': 5}, 'f': [{'g': '6'}]}})