【问题标题】:Converting string with leading-zero integer to json将具有前导零整数的字符串转换为json
【发布时间】:2019-07-08 10:06:08
【问题描述】:

我使用 json-library 将字符串转换为 json 对象:

a = '{"index":1}'
import json
json.loads(a)
{'index': 1}

但是,如果我改为将字符串 a 更改为包含前导 0,那么它就会崩溃:

a = '{"index":01}'
import json
json.loads(a)
>>> JSONDecodeError: Expecting ',' delimiter

我认为这是因为如果整数以前导零开头,则它是无效的 JSON,如 thread 中所述。

有没有办法解决这个问题?如果不是,那么我想最好的方法是首先通过正则表达式从字符串中删除任何前导零,然后转换为 json?

【问题讨论】:

  • 只有index键受此影响吗?
  • @aws_apprentice 不,以上只是一个示例。我的 JSON 字符串很长,所以理想情况下应该编写一个函数来为字符串中的任何数字加上引号(我猜?)
  • 你能用你的 json 字符串分享一个 pastebin 链接吗?
  • 你必须使用你自己的解码器在这里查看类似的帖子。 stackoverflow.com/questions/45068797/…
  • @AbinayaDevarajan 一个数字不能以0 开头,除非它只是0 或以0. 开头,这在json 模块中非常重要。上述问题中描述的技术仅在json 识别出该数字是有效的 JSON 数字文字时才有效。很难绕过这个限制,您必须放弃使用内部json.scanner 模块的C 实现,并在扫描仪的Python 实现中修改全局正则表达式。这是一个非常丑陋的黑客攻击。

标签: python json regex


【解决方案1】:

JSON 中数字文字中的前导 0 无效,除非数字文字只是字符 0 或以 0. 开头。 Python json 模块非常严格,因为它不会接受这样的数字文字。部分原因是前导 0 有时用于表示八进制而不是十进制。反序列化此类数字可能会导致意外的编程错误。也就是说,应该将010 解析为数字8(八进制)还是10(十进制)。

您可以创建一个解码器来满足您的需求,但您需要大量破解json 模块或重写其大部分内部结构。无论哪种方式,您都会看到性能下降,因为您将不再使用该模块的 C 实现。

下面是一个可以解码 JSON 的实现,其中包含带有任意数量前导零的数字。

import json
import re
import threading

# a more lenient number regex (modified from json.scanner.NUMBER_RE)
NUMBER_RE = re.compile(
    r'(-?(?:\d*))(\.\d+)?([eE][-+]?\d+)?',
    (re.VERBOSE | re.MULTILINE | re.DOTALL))


# we are going to be messing with the internals of `json.scanner`. As such we
# want to return it to its initial state when we're done with it, but we need to
# do so in a thread safe way.
_LOCK = threading.Lock()
def thread_safe_py_make_scanner(context, *, number_re=json.scanner.NUMBER_RE):
    with _LOCK:
        original_number_re = json.scanner.NUMBER_RE
        try:
            json.scanner.NUMBER_RE = number_re
            return json.scanner._original_py_make_scanner(context)
        finally:
            json.scanner.NUMBER_RE = original_number_re

json.scanner._original_py_make_scanner = json.scanner.py_make_scanner
json.scanner.py_make_scanner = thread_safe_py_make_scanner


class MyJsonDecoder(json.JSONDecoder):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # overwrite the stricter scan_once implementation
        self.scan_once = json.scanner.py_make_scanner(self, number_re=NUMBER_RE)


d = MyJsonDecoder()
n = d.decode('010')
assert n == 10

json.loads('010') # check the normal route still raise an error

我要强调的是,您不应将此作为正确的解决方案。相反,它是一种快速破解方法,可帮助您解码几乎有效但不完全有效的格式错误的 JSON。如果由于某种原因无法以有效形式重新创建 JSON,这将非常有用。

【讨论】:

    【解决方案2】:

    首先,在 JSON 上使用正则表达式是邪恶的,几乎和杀死一只小猫一样糟糕。

    如果您想将01 表示为有效的 JSON 值,请考虑使用此结构:

    a = '{"index" : "01"}'
    import json
    json.loads(a)
    

    如果您需要字符串文字 01 表现得像一个数字,那么请考虑在 Python 脚本中将其转换为整数。

    【讨论】:

    • 我的 JSON 字符串很长,手动执行此操作并不可行。有没有办法自动化这个?
    • 我认为问题可能在于您的 JSON 字符串的来源,而不是您的 Python 代码。您是否有机会更改导出以便将“数字”视为字符串?
    • 为什么使用正则表达式是邪恶的?如果字符串没有任何其他数字,那么我认为正则表达式将是最简单的方法
    • @ninesalt JSON 内容可能是嵌套的。不能给出正则表达式会失败的边缘情况,但我宁愿避免这种机会。
    • 我从库中获取 JSON 字符串,所以很遗憾无法控制它。但是,它不是嵌套的,所以最好编写一个正则表达式来处理整数?
    【解决方案3】:

    How to convert string int JSON into real int with json.loads 请看上面的帖子 您需要使用自己的解码器版本。

    更多信息可以在这里找到,在 github https://github.com/simplejson/simplejson/blob/master/index.rst

    c = '{"value": 02}'
    value= json.loads(json.dumps(c))
    print(value)
    

    这似乎有效.. 很奇怪

    > >>> c = '{"value": 02}'
    > >>> import json
    > >>> value= json.loads(json.dumps(c))
    > >>> print(value) {"value": 02}
    > >>> c = '{"value": 0002}'
    > >>> value= json.loads(json.dumps(c))
    > >>> print(value) {"value": 0002}
    

    正如@Dunes 所指出的,负载会产生字符串作为结果,这不是有效的解决方案。 不过,

    DEMJSON 似乎可以正确解码。 https://pypi.org/project/demjson/ -- 替代方式

    >>> c = '{"value": 02}'
    >>> import demjson
    >>> demjson.decode(c)
    {'value': 2}
    

    【讨论】:

    • 因为 c 是一个字符串,而不是包含 int 的字典。字符串没有与数字相同的限制。即使您转储了字典,它仍然无济于事,因为 json 模块将发出有效的 JSON,而 02 不是。
    猜你喜欢
    • 2014-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多