Недопустимый начальный 0 в числовом литерале в JSON, если только числовой литерал не является только символом 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 в правильной форме по какой-то причине невозможно.