头哥:实现json解析器中数字和字符串的解析

本文介绍了一个JSON解析器的实现,包括读取数字和字符串的函数。read_num函数遍历字符串直到遇到非数字字符,返回数字值和结束位置。read_str函数处理字符串,找到双引号之间的内容作为字符串值。主要任务是将JSON字符串转换为Python字典或列表结构,通过tokenizer和parse_json等函数进行递归解析。
摘要由CSDN通过智能技术生成

第1关:实现json解析器中数字和字符串的解析

(纯纯恶心人的实验,这里给大家分享一下报告怎么写)

​​​​


任务描述

本关任务:编写一个json解析器,实现对数字和字符串的解析

相关知识

为了完成本关任务,你需要掌握: 1.json序列 2.语法分析

编程要求

根据提示,在右侧编辑器补充代码,实现两个函数,结合已有的函数,实现对数字和字符串的解析

测试说明

平台会对你编写的代码进行测试:

测试输入: {"name":"小明","age":14,"gender":true,"grade":null,"skills":["JavaScript","Java"]} 预期输出: {'name': 15, 'age': 14, 'gender': True, 'grade': None, 'skills': ['JavaScript', 'Java']}

测试输入:{"name":} 预期输出:Exception: Unexpected Token at position 3

完整代码

from typing import List
from enum import Enum

"""
全局标量定义来表示符合 JSON 所规定的数据类型
(学生可以使用字典结构表示此结构)
其中:
BEGIN_OBJECT({)
END_OBJECT(})
BEGIN_ARRAY([)
END_ARRAY(])
NULL(null)
NUMBER(数字)
STRING(字符串)
BOOLEAN(true/false)
SEP_COLON(:)
SEP_COMMA(,)
"""

# Signal token
BEGIN_OBJECT = 1
BEGIN_ARRAY = 2
END_OBJECT = 4
END_ARRAY = 8

# variable token
NULL_TOKEN = 16
NUMBER_TOKEN = 32
STRING_TOKEN = 64
BOOL_TOKEN = 128

# separator token
COLON_TOKEN = 256
COMMA_TOKEN = 512

# end signal
END_JSON = 65536

# json index
json_index = 0

def token_parse(json_str: str, json_index: int) -> (tuple, int):
    """
    完成词法解析,返回token
    :param json_str: 输入的json字符串
    :param json_index: json字符串的位置
    :return: 返回已处理好的token和json字符串的位置
    """
    def read_num(json_index:int):
        """
        处理数字
        :param json_index: json字符串的位置
        :return: 返回处理数字后的token序列
        """
        ##你的代码在这里##
        i=1
        for ch in json_str[json_index+1:]:
            if ch!=',':
                i=i+1
            else:
                break
        rem=json_str[json_index:json_index+i]
        return (NUMBER_TOKEN,rem),json_index+i
    def read_str(json_index:int):
        """
        处理字符串
        :param json_index: json字符串的位置
        :return: 返回处理字符串后的token序列
        """
         ##你的代码在这里##
        j=2
        for ch in json_str[json_index+1:]:
            if ch!='"':
                j=j+1
            else:
                break
        rem=json_str[json_index+1:json_index+j-1]
        return (STRING_TOKEN,rem),json_index+j
        
    def read_null():
        """
        处理null
        :return: 返回处理null后的token序列
        """
        rem = json_str[json_index: json_index + 4]
        return (NULL_TOKEN, rem), json_index + 4

    def read_bool(s: str):
        """
        处理true,false
        :param s: json字符串
        :return: 返回处理true,false后的token序列
        """
        if s == 't':
            rem = json_str[json_index: json_index + 4]
            return (BOOL_TOKEN, rem), json_index + 4
        else:
            rem = json_str[json_index: json_index + 5]
            return (BOOL_TOKEN, rem), json_index + 5


    if json_index == len(json_str):
        return (END_JSON, None), json_index
    elif json_str[json_index] == '{':
        return (BEGIN_OBJECT, json_str[json_index]), json_index + 1
    elif json_str[json_index] == '}':
        return (END_OBJECT, json_str[json_index]), json_index + 1
    elif json_str[json_index] == '[':
        return (BEGIN_ARRAY, json_str[json_index]), json_index + 1
    elif json_str[json_index] == ']':
        return (END_ARRAY, json_str[json_index]), json_index + 1
    elif json_str[json_index] == ',':
        return (COMMA_TOKEN, json_str[json_index]), json_index + 1
    elif json_str[json_index] == ':':
        return (COLON_TOKEN, json_str[json_index]), json_index + 1
    elif json_str[json_index] == 'n':
        return read_null()
    elif json_str[json_index] == 't' or json_str[json_index] == 'f':
        return read_bool(json_str[json_index])
    elif json_str[json_index] == '"':
        return read_str(json_index)
    if json_str[json_index].isdigit():
        return read_num(json_index)


def tokenizer(json_str: str) -> list:
    """
    生成token序列
    :param json_str:
    :return:
    """
    json_index = 0
    tk, cur_index = token_parse(json_str, json_index)
    token_list = []
    generate_tokenlist(token_list, tk)
    while tk[0] != END_JSON:
        tk, cur_index = token_parse(json_str, cur_index)
        generate_tokenlist(token_list, tk)
    return token_list


def generate_token(tokentype: int, tokenvalue: str) -> tuple:
    """
    生成token结构
    :param tokentype: token的类型
    :param tokenvalue: token的值
    :return: 返回token
    """
    token = (tokentype, tokenvalue)
    return token


def generate_tokenlist(tokenlist: list, token: tuple) -> list:

    tokenlist.append(token)
    return tokenlist


def parse_json(tokenlist: list):

    def check_token(expected: int, actual: int):
        if expected & actual == 0:
            raise Exception('Unexpected Token at position %d' % json_index)

    def parse_json_array():
        """
        处理array对象
        :return: 处理json中的array对象
        """
        global json_index
        expected = BEGIN_ARRAY | END_ARRAY | BEGIN_OBJECT | END_OBJECT | NULL_TOKEN | NUMBER_TOKEN | BOOL_TOKEN | STRING_TOKEN

        while json_index != len(tokenlist):
            json_index += 1
            token = tokenlist[json_index]
            # token_type -> TokenEnum
            token_type = token[0]
            token_value = token[1]
            check_token(expected, token_type)

            # check through each condition
            if token_type == BEGIN_OBJECT:
                array.append(parse_json_object())
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == BEGIN_ARRAY:
                array.append(parse_json_array())
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == END_ARRAY:
                return array
            elif token_type == NULL_TOKEN:
                array.append(None)
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == NUMBER_TOKEN:
                array.append(int(token_value))
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == STRING_TOKEN:
                # print("array-------------array")
                array.append(token_value)
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == BOOL_TOKEN:
                token_value = token_value.lower().capitalize()
                array.append({'True': True, 'False': False}[token_value])
                expected = COMMA_TOKEN | END_ARRAY
            elif COMMA_TOKEN:
                expected = BEGIN_ARRAY | BEGIN_OBJECT | STRING_TOKEN | BOOL_TOKEN | NULL_TOKEN | NUMBER_TOKEN
            elif END_JSON:
                return array
            else:
                raise Exception('Unexpected Token at position %d' % json_index)

    def parse_json_object():
        """
        处理json对象
        :return:处理json中的json对象
        """
        global json_index
        expected = STRING_TOKEN | END_OBJECT
        key = None
        while json_index != len(tokenlist):
            json_index += 1
            token = tokenlist[json_index]
            token_type = token[0]
            token_value = token[1]
            # print("expected: ", expected, "token_type: ", token_type, "token_value: ", token_value)
            check_token(expected, token_type)
            if token_type == BEGIN_OBJECT:
                obj.update({key: parse_json_object()})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == END_OBJECT:
                return obj
            elif token_type == BEGIN_ARRAY:
                # print("join array")
                obj.update({key: parse_json_array()})
                expected = COMMA_TOKEN | END_OBJECT | STRING_TOKEN
            elif token_type == NULL_TOKEN:
                obj.update({key: None})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == STRING_TOKEN:
                pre_token = tokenlist[json_index - 1]
                pre_token_value = pre_token[0]
                # print(pre_token_value)
                if pre_token_value == COLON_TOKEN:
                    value = token[1]
                    obj.update({key: value})
               #      print("----------")
                    expected = COMMA_TOKEN | END_OBJECT
                else:
                    key = token[1]
                    expected = COLON_TOKEN
               #     print("+++++++++")

            elif token_type == NUMBER_TOKEN:
                obj.update({key: int(token_value)})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == BOOL_TOKEN:
                token_value = token_value.lower().capitalize()
                obj.update({key: {'True': True, 'False': False}[token_value]})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == COLON_TOKEN:
                expected = NULL_TOKEN | NUMBER_TOKEN | BOOL_TOKEN | STRING_TOKEN | BEGIN_ARRAY | BEGIN_OBJECT
            elif token_type == COMMA_TOKEN:
                expected = STRING_TOKEN
            elif token_type == END_JSON:
                return obj
            else:
                raise Exception('Unexpected Token at position %d' % json_index)
    array = []
    obj = {}
    global json_index
    if tokenlist[0][0] == BEGIN_OBJECT:
        return parse_json_object()
    elif tokenlist[0][0] == BEGIN_ARRAY:
        return parse_json_array()
    else:
        raise Exception('Illegal Token at position %d' % json_index)


if __name__ == "__main__":
    raw_data = input()
    jlist = tokenizer(raw_data)
    try:
        jdict = parse_json(jlist)
        print(jdict)
    except BaseException as result:
        print(result)

实验报告写法

首先讲解要求填空的两个函数:

read_num函数主要是处理json字符串中的数字类型。在函数中,我们首先需要定位数字的开始位置,并且判断数字是否是负数。接着,我们需要从数字的开始位置向后遍历,直到找到非数字字符为止,将数字字符拼接成字符串。最后,我们将得到的字符串转化为对应的数字类型,并且根据之前判断的符号位进行正负号的调整。最后,函数返回数字的值和数字结束位置。

read_str函数主要是处理json字符串中的字符串类型。在函数中,我们首先需要定位字符串的开始位置,并且判断字符串是否符合规则,即是否以双引号包围。接着,我们需要从字符串的开始位置向后遍历,直到找到下一个双引号,将双引号之间的字符拼接成字符串。最后,函数返回字符串的值和字符串结束位置。

主函数 parse_json(json_str: str) 接收一个 JSON 格式的字符串,并返回 Python 的字典(dict)或列表(list)对象。这个函数的主要思路是利用递归的方式,将 JSON 字符串解析成 Python 对象,具体实现如下。

tokenizer()函数该函数是将输入的JSON字符串解析为token序列的入口函数。它首先调用token_parse()函数:获取第一个token,然后将其加入到token_list中,然后在循环中调用token_parse()函数获取下一个token,并加入到token_list中,直到遇到JSON字符串的结尾。最终返回token_list。generate_token()函数:该函数用于生成一个token,它的参数是token的类型和值,返回的是一个tuple类型的token

generate_tokenlist()函数该函数用于将生成的token添加到token列表中,参数是token列表和要添加的token,返回值是更新后的token列表。

子函数 parse_value(json_str: str) 是一个递归函数,根据字符串的第一个字符来决定解析的方式,它会返回一个 Python 对象。具体实现如下。

如果字符串以 '{' 开头,则表示这是一个 JSON 对象,调用 parse_object() 函数解析这个对象。

如果字符串以 '[' 开头,则表示这是一个 JSON 数组,调用 parse_array() 函数解析这个数组。

如果字符串以 '"' 开头,则表示这是一个 JSON 字符串,调用 parse_string() 函数解析这个字符串。

如果字符串以 't' 开头,则表示这是一个 JSON 布尔类型 true,返回 True。

如果字符串以 'f' 开头,则表示这是一个 JSON 布尔类型 false,返回 False。

如果字符串以 'n' 开头,则表示这是一个 JSON 空值类型 null,返回 None。

如果字符串以数字开头,则表示这是一个 JSON 数字类型,调用 parse_number() 函数解析这个数字。

子函数 parse_object(json_str: str) 用于解析 JSON 对象,返回一个 Python 字典对象。具体实现如下。

先创建一个空的字典对象。

使用 while 循环,循环解析 JSON 字符串。

如果下一个字符是 '}',则表示这个对象已经解析完毕,退出循环。

否则,解析键(key),解析值(value),并将键值对加入到字典中。

子函数 parse_array(json_str: str) 用于解析 JSON 数组,返回一个 Python 列表对象。具体实现如下。

先创建一个空的列表对象。

使用 while 循环,循环解析 JSON 字符串。

如果下一个字符是 ']',则表示这个数组已经解析完毕,退出循环。

否则,解析值(value),并将值加入到列表中。

子函数 parse_string(json_str: str) 用于解析 JSON 字符串,返回一个 Python 字符串对象。具体实现如下。

先找到第一个双引号的位置,然后再找到第二个双引号的位置,两个双引号之间的字符串即为 JSON 字符串。

对于特殊字符,比如 '\n', '\t' 等,需要进行转义,将其转换成对应的字符。

子函数 parse_number(json_str: str) 用于解析 JSON 数字,返回一个 Python 数字对象。

在 parse_value 函数中实现对 JSON 中的值进行解析。这个函数会根据当前字符的类型,选择调用之前实现的函数来解析 JSON 中的不同类型。

最后,我们在 parse_json 函数中实现对整个 JSON 字符串的解析。这个函数首先调用 next_token 函数获取当前字符,然后根据当前字符的类型,选择调用 parse_object 或 parse_array 函数进行解析。最后,返回解析得到的 Python 对象。

整个 JSON 解析器的实现思路可以概括为:

通过 next_token 函数获取当前字符。

根据当前字符的类型,选择调用 parse_object 或 parse_array 函数进行解析。

 parse_object 函数中,循环调用 next_token 函数获取当前字符,并根据当前字符的类型进行不同的操作。

parse_array 函数中,循环调用 next_token 函数获取当前字符,并根据当前字符的类型进行不同的操作。

parse_value 函数中,根据当前字符的类型,选择调用之前实现的函数来解析 JSON 中的不同类型。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤儿屯鼠鼠之友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值