随手实现一个JSON解析器

class JsonParser:
    def __init__(self, s):
        self.s = s
        self.idx = 0

    def match(self, t):
        if self.curr_char() == t:
            self.idx += 1
        else:
            print(self.curr_char())
            print('match ERROR', t)
            exit()

    def curr_char(self):
        while self.s[self.idx].isspace():
            self.idx += 1
        return self.s[self.idx]

    def common_parse(self):
        """
        递归下降分析: str-->json
        """
        if self.curr_char() == '[':
            return self.parse_list()
        elif self.curr_char() == '{':
            return self.parse_dict()
        else:
            return self.parse_basic()

    def parse_dict(self):
        self.match('{')
        rtv = {}
        while True:
            key = self.parse_basic()
            self.match(':')
            value = self.common_parse()
            rtv[key] = value
            if self.curr_char() != ',':
                break
            self.match(',')
        self.match('}')
        return rtv

    def parse_list(self):
        self.match('[')
        rtv = []
        while True:
            item = self.common_parse()
            rtv.append(item)
            if self.curr_char() != ',':
                break
            self.match(',')
        self.match(']')
        return rtv

    def parse_basic(self):
        """
        int, none, bool, str
        """
        tmp = self.curr_char()
        if tmp.isdigit():
            self.idx += 1
            while self.curr_char().isdigit():
                tmp += self.curr_char()
                self.idx += 1
            return int(tmp)
        elif tmp == 'n':
            for c in 'null':
                self.match(c)
            return None
        elif tmp == 't':
            for c in 'true':
                self.match(c)
            return True
        elif tmp == 'f':
            for c in 'false':
                self.match(c)
            return False
        elif tmp == '"':
            self.match('"')
            tmp = ''
            while self.curr_char() != '"':
                tmp += self.curr_char()
                self.idx += 1
            self.match('"')
            return tmp


class JsonDump:
    @classmethod
    def dump(cls, o):
        return ''.join([s for s in cls.common_dump(o)])

    @classmethod
    def common_dump(cls, o):
        """
        深度优先遍历: json-->str
        """
        if isinstance(o, list):
            yield from cls.dump_list(o)
        elif isinstance(o, dict):
            yield from cls.dump_dict(o)
        else:
            yield from cls.dump_basic(o)

    @classmethod
    def dump_list(cls, o):
        idx, length = 0, len(o)
        yield '['
        for item in o:
            yield from cls.common_dump(item)
            idx += 1
            if idx < length:
                yield ','
        yield ']'

    @classmethod
    def dump_dict(cls, o):
        idx, length = 0, len(o)
        yield '{'
        for k, v in o.items():
            yield from cls.common_dump(k)
            yield ':'
            yield from cls.common_dump(v)
            idx += 1
            if idx < length:
                yield ','
        yield '}'

    @classmethod
    def dump_basic(cls, o):
        if o == True:
            yield 'true'
        elif o == False:
            yield 'false'
        elif o == None:
            yield 'null'
        elif isinstance(o, str):
            yield '"'
            yield o
            yield '"'
        elif isinstance(o, int):
            yield str(o)


if __name__ == '__main__':
    s = '{"hello": "world", "game": "war", "LIST": [1, 2, 3, {"Bang": false}]}'
    s2 = '{"paths":[{"path":"/:firewall:13","mac":false,"mac_users":[]}],"data":{"action":"add_rule","protocol":"TCP","cidr":"116.116.116.12/32","port_range":"80/8080","policy":"Accept","desc":"test"}}'
    jp = JsonParser(s2)
    print(s2)
    from pprint import pprint
    pprint(jp.common_parse())

    o = {'hello': 'world', 'game': 'war', 'LIST': [1, 2, 3, {'Bang': False}]}
    print(o)
    print(JsonDump.dump(o))

运行效果:

E:\workspace\sept>python json_parse.py
{"paths":[{"path":"/:firewall:13","mac":false,"mac_users":[]}],"data":{"action":"add_rule","protocol":"TCP","cidr":"116.116.116.12/32","por
t_range":"80/8080","policy":"Accept","desc":"test"}}
{'data': {'action': 'add_rule',
          'cidr': '116.116.116.12/32',
          'desc': 'test',
          'policy': 'Accept',
          'port_range': '80/8080',
          'protocol': 'TCP'},
 'paths': [{'mac': False, 'mac_users': [None], 'path': '/:firewall:13'}]}
{'hello': 'world', 'game': 'war', 'LIST': [1, 2, 3, {'Bang': False}]}
{"hello":"world","game":"war","LIST":[true,2,3,{"Bang":false}]}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容