repo: init
This commit is contained in:
4
asjsonp/__init__.py
Executable file
4
asjsonp/__init__.py
Executable file
@ -0,0 +1,4 @@
|
||||
from asjsonp.module import loads
|
||||
|
||||
|
||||
__all__ = ["loads"]
|
||||
4
asjsonp/__main__.py
Executable file
4
asjsonp/__main__.py
Executable file
@ -0,0 +1,4 @@
|
||||
from asjsonp.module import loads
|
||||
|
||||
|
||||
print(loads(open("test.json", "r").read()))
|
||||
125
asjsonp/module.py
Executable file
125
asjsonp/module.py
Executable file
@ -0,0 +1,125 @@
|
||||
__all__ = ["loads"]
|
||||
|
||||
|
||||
def js2py(obj: str):
|
||||
"""
|
||||
Convert a JSON string to a Python object.
|
||||
|
||||
This follows the simple approach defined in https://docs.python.org/3/library/json.html#encoders-and-decoders
|
||||
"""
|
||||
if obj == "true":
|
||||
return True
|
||||
elif obj == "false":
|
||||
return False
|
||||
elif obj == "null":
|
||||
return None
|
||||
elif obj == "NaN":
|
||||
return float("nan")
|
||||
elif obj == "Infinity":
|
||||
return float("inf")
|
||||
elif obj == "-Infinity":
|
||||
return float("-inf")
|
||||
elif obj.isnumeric():
|
||||
return int(obj)
|
||||
elif obj.lower().replace(".", "").replace("e", "").replace("-", "").isnumeric():
|
||||
return float(obj)
|
||||
else:
|
||||
raise ValueError(f"Invalid JSON value: {obj}")
|
||||
|
||||
|
||||
def loads(s: str):
|
||||
result: list | dict = []
|
||||
first_open: bool = False
|
||||
multiple_object_root: bool = False
|
||||
parents: list = []
|
||||
current: dict | list = result
|
||||
dict_current_key: str = None
|
||||
dict_reading_value: str = None
|
||||
# Set the value so Pylance can be happy.
|
||||
current_text: str = ""
|
||||
is_reading_string: bool = False
|
||||
# Ignore the rest of the string line if it's a comment
|
||||
prev_char: str = ""
|
||||
ignore_rest: bool = False
|
||||
|
||||
def handle_reading_value():
|
||||
nonlocal dict_reading_value
|
||||
nonlocal dict_current_key
|
||||
if dict_reading_value is not None and dict_reading_value.strip():
|
||||
value = js2py(dict_reading_value)
|
||||
if dict_current_key:
|
||||
current[dict_current_key] = value
|
||||
else:
|
||||
current.append(value)
|
||||
dict_reading_value = None
|
||||
dict_current_key = None
|
||||
|
||||
for char in s:
|
||||
if ignore_rest:
|
||||
if char == "\n":
|
||||
ignore_rest = False
|
||||
elif is_reading_string:
|
||||
# Handle string closing quote
|
||||
if char == '"':
|
||||
is_reading_string = False
|
||||
if isinstance(current, dict):
|
||||
if not dict_current_key:
|
||||
dict_current_key = current_text
|
||||
else:
|
||||
current[dict_current_key] = current_text
|
||||
dict_current_key = None
|
||||
dict_reading_value = None
|
||||
else:
|
||||
current.append(current_text)
|
||||
dict_reading_value = None
|
||||
current_text = ""
|
||||
else:
|
||||
current_text += char
|
||||
# Handle object & array types
|
||||
elif char in ["{", "["]:
|
||||
obj: dict | list
|
||||
match char:
|
||||
case "{":
|
||||
if not first_open:
|
||||
first_open = True
|
||||
obj = {}
|
||||
case "[":
|
||||
if not first_open:
|
||||
first_open = True
|
||||
multiple_object_root = True
|
||||
obj = []
|
||||
if isinstance(current, list):
|
||||
current.append(obj)
|
||||
elif isinstance(current, dict):
|
||||
current[dict_current_key] = obj
|
||||
parents.append(current)
|
||||
# Reference to the current dict
|
||||
if isinstance(current, list):
|
||||
current = current[-1]
|
||||
elif isinstance(current, dict):
|
||||
current = current[dict_current_key]
|
||||
dict_current_key = None
|
||||
# Handle object and array closing bracket
|
||||
elif char in ["}", "]"]:
|
||||
# Switch reference back to the parent dict
|
||||
handle_reading_value()
|
||||
current = parents.pop()
|
||||
# Handle string opening quote
|
||||
elif char == '"':
|
||||
is_reading_string = True
|
||||
current_text = ""
|
||||
elif char == ":":
|
||||
dict_reading_value = ""
|
||||
elif char == ",":
|
||||
handle_reading_value()
|
||||
elif char == "/":
|
||||
if prev_char == "/":
|
||||
ignore_rest = True
|
||||
else:
|
||||
if dict_reading_value is not None:
|
||||
if char.strip():
|
||||
dict_reading_value += char
|
||||
prev_char = char
|
||||
if not multiple_object_root:
|
||||
result = result[0]
|
||||
return result
|
||||
Reference in New Issue
Block a user