2022/05/03 JSON Parser を作ってみた

Python による JSON Parser の実装

※ソースコード全体はgithubを参照してください。

こんにちは。ねこまたです。PytnonでJSONをパースできるようにしました。space、string、array、null、boolean、objectのパースを実装したので、以下にソースコードの一部とともに実装の際考えたことなどを書いていきます。

準備

def is_digit(c):
    # 文字列の大小比較
    return "0" <= c and c <= "9"

大小比較の表現を用いてJSONが数字であるかを調べます。

class Parser:
    def __init__(self, s) -> None:
        self.s = s
        self.pos = 0

self.sは読み込む文字列、self.posは現在の位置を示します。これを用いて後に行うパースで文字を一つ進める処理を行います。

def peek(self):
    if self.pos < len(self.s):
        return self.s[self.pos]
    else:
        raise ParseError()

self.posが読み込む文字列の長さより小さいとき、読み込む文字列のself.pos番目(=現在の位置)を返す関数を定義します。

1. スペースのパース

def spaces(self):
    while True:
        try:
            c = self.peek()
        except ParseError:
            break
        if c == " " or c == "\n" or c == "\t" or c == "\r":
            self.pos += 1
        else:
            break

スペースを無視するようにします。

2. stringのパース

stringをパースするためには、文字であるcharのパースを行い、string関数の中でchar関数を呼び出す必要があります。

def char(self):
    c = self.peek()
    if c == "\"":
        raise ParseError()
    if c == "\\":
        self.pos += 1
        c = self.peek()
        if c == "n":
            self.pos += 1
            return "\n"
        if c == "r":
            self.pos += 1
            return "\r"
        if c == "t":
            self.pos += 1
            return "\t"
        if c == "\\":
            self.pos += 1
            return "\\"
        if c == "\"":
            self.pos += 1
            return "\""
        raise ParseError()
    else:
        self.pos += 1
        return c

ここでは文字列が"のときエラーを返し、\n\r\t\\\"が出てきた場合はそれぞれ中身を変えずに返し、その他のエスケープシーケンス が出てきた場合にもエラーを返しています。

def string(self):
    res = ""
    c = self.peek()
    if not c == "\"":
        raise ParseError()
    self.pos += 1
    while True:
        c = self.peek()
        if c == "\"":
            self.pos += 1
            return res
        x = self.char()
        res += x 

まず self.peek 関数を呼び出して文字列の先頭の文字を取得し、" から始まっていなければエラーを返します。" から始まっていればJSONの文字列であることから、self.pos を1進めてパースを続けます。その後、char 関数を呼び出し、文字列の末尾が"になるまでパースします。文字列の中でパースを終えた部分の文字をres に追加していき、最後にres を返します。これで文字列のパースが完了します。

3. arrayのパース

array をパースするためには、, で区切られた配列の要素を先頭から順に調べる必要があります。

def array(self):
    res = []
    c = self.peek()
    if c != "[":
        raise ParseError()
    self.pos += 1
    self.spaces()
    c = self.peek()
    if c == "]":
        self.pos += 1
        return res
    x = self.json()
    res.append(x)
    while True:
        self.spaces()
        c = self.peek()
        if c == "]":
            self.pos += 1
            return res
        if c != ",":
            raise ParseError()
        self.pos += 1
        self.spaces()
        x = self.json()
        res.append(x)

まず self.peek 関数を呼び出して文字列の先頭の文字を取得し、[ から始まっていなければエラーを返します。self.pos を一つ進め、spaces 関数を呼び出し、配列の中に含まれるスペースを無視します。次に、もう一度self.peek 関数を呼び出し、配列の末尾が] になっていればres を返して終了します。末尾が] でなければjson 関数を呼び出し、resx を追加します。次に、再びスペースを無視し、配列の先頭を取得します。while の中では、配列の末尾が] になるまでパースを続けます。配列の先頭[ を除いた先頭の文字の次の文字が, でなければ エラーを返し、] が再び現れるまでパースを続けます。

def json(self):
    c = self.peek()
    if c == "[":
        return self.array()
    if c == "t" or c == "f":
        return self.boolean()
    if c == "n":
        return self.null()
    if c == "\"":
        return self.string()
    if c == "{":
        return self.object()
    return self.parse_natural()

json関数

4. 実際に使ってみる

正常に動いているか調べるため、自分のTwitterのユーザー情報を取得し、パースを行いました。

入力

{"id":1346478670240616400,"id_str":"1346478670240616449","name":"ねこまた","screen_name":"what_is_pyoni","location":"","profile_location":null,"description":"https://t.co/9roPByIsvY Okayama Univ.🌏 B1 / OUCRC","url":null,"entities":{"description":{"urls":[{"url":"https://t.co/9roPByIsvY","expanded_url":"http://kyon.earth","display_url":"kyon.earth","indices":[0,23]}]}},"protected":false,"followers_count":92,"friends_count":112,"listed_count":0,"created_at":"Tue Jan 05 15:28:40 +0000 2021","favourites_count":11013,"utc_offset":null,"time_zone":null,"geo_enabled":true,"verified":false,"statuses_count":1340,"lang":null,"status":{"created_at":"Sun May 01 06:18:35 +0000 2022","id":1520648861420687400,"id_str":"1520648861420687360","text":"RT @Takano_Shiho: 夏の宝石 https://t.co/zSDV208rAG","truncated":false,"extended_entities":{"media":[{"id":1520564805353885700,"id_str":"1520564805353885696","indices":[23,46],"media_url":"http://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg","media_url_https":"https://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"},"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"}},"source_status_id":1520564817349677000,"source_status_id_str":"1520564817349677057","source_user_id":793854134,"source_user_id_str":"793854134"},{"id":1520564805475602400,"id_str":"1520564805475602434","indices":[23,46],"media_url":"http://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg","media_url_https":"https://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"large":{"w":2048,"h":1152,"resize":"fit"},"medium":{"w":1200,"h":675,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"}},"source_status_id":1520564817349677000,"source_status_id_str":"1520564817349677057","source_user_id":793854134,"source_user_id_str":"793854134"},{"id":1520564805534290000,"id_str":"1520564805534289920","indices":[23,46],"media_url":"http://pbs.twimg.com/media/FRohomPVEAASBwR.jpg","media_url_https":"https://pbs.twimg.com/media/FRohomPVEAASBwR.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"},"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"}},"source_status_id":1520564817349677000,"source_status_id_str":"1520564817349677057","source_user_id":793854134,"source_user_id_str":"793854134"},{"id":1520564805609791500,"id_str":"1520564805609791488","indices":[23,46],"media_url":"http://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg","media_url_https":"https://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"}},"source_status_id":1520564817349677000,"source_status_id_str":"1520564817349677057","source_user_id":793854134,"source_user_id_str":"793854134"}]},"source":"<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"geo":null,"coordinates":null,"place":null,"contributors":null,"retweeted_status":{"created_at":"Sun May 01 00:44:37 +0000 2022","id":1520564817349677000,"id_str":"1520564817349677057","text":"夏の宝石 https://t.co/zSDV208rAG","truncated":false,"extended_entities":{"media":[{"id":1520564805353885700,"id_str":"1520564805353885696","indices":[5,28],"media_url":"http://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg","media_url_https":"https://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"},"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"}}},{"id":1520564805475602400,"id_str":"1520564805475602434","indices":[5,28],"media_url":"http://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg","media_url_https":"https://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"large":{"w":2048,"h":1152,"resize":"fit"},"medium":{"w":1200,"h":675,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"}}},{"id":1520564805534290000,"id_str":"1520564805534289920","indices":[5,28],"media_url":"http://pbs.twimg.com/media/FRohomPVEAASBwR.jpg","media_url_https":"https://pbs.twimg.com/media/FRohomPVEAASBwR.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"},"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"}}},{"id":1520564805609791500,"id_str":"1520564805609791488","indices":[5,28],"media_url":"http://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg","media_url_https":"https://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg","url":"https://t.co/zSDV208rAG","display_url":"pic.twitter.com/zSDV208rAG","expanded_url":"https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1","type":"photo","sizes":{"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":680,"h":383,"resize":"fit"}}}]},"source":"<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":76,"favorite_count":589,"favorited":false,"retweeted":false,"possibly_sensitive":false,"lang":"ja"},"is_quote_status":false,"retweet_count":76,"favorite_count":0,"favorited":false,"retweeted":false,"possibly_sensitive":false,"lang":"ja"},"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"F5F8FA","profile_background_image_url":null,"profile_background_image_url_https":null,"profile_background_tile":false,"profile_image_url":"http://pbs.twimg.com/profile_images/1511726514634588166/0L3xPaQ4_normal.jpg","profile_image_url_https":"https://pbs.twimg.com/profile_images/1511726514634588166/0L3xPaQ4_normal.jpg","profile_banner_url":"https://pbs.twimg.com/profile_banners/1346478670240616449/1650041603","profile_link_color":"1DA1F2","profile_sidebar_border_color":"C0DEED","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"has_extended_profile":true,"default_profile":true,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none","withheld_in_countries":[]}

出力

{'id': 1346478670240616400, 'id_str': '1346478670240616449', 'name': 'ねこまた', 'screen_name': 'what_is_pyoni', 'location': '', 'profile_location': None, 'description': 'https://t.co/9roPByIsvY Okayama Univ.🌏 B1 / OUCRC', 'url': None, 'entities': {'description': {'urls': [{'url': 'https://t.co/9roPByIsvY', 'expanded_url': 'http://kyon.earth', 'display_url': 'kyon.earth', 'indices': [0, 23]}]}}, 'protected': False, 'followers_count': 92, 'friends_count': 112, 'listed_count': 0, 'created_at': 'Tue Jan 05 15:28:40 +0000 2021', 'favourites_count': 11013, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 1340, 'lang': None, 'status': {'created_at': 'Sun May 01 06:18:35 +0000 2022', 'id': 1520648861420687400, 'id_str': '1520648861420687360', 'text': 'RT @Takano_Shiho: 夏の宝石 https://t.co/zSDV208rAG', 'truncated': False, 'extended_entities': {'media': [{'id': 1520564805353885700, 'id_str': '1520564805353885696', 'indices': [23, 46], 'media_url': 'http://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}}, 'source_status_id': 1520564817349677000, 'source_status_id_str': '1520564817349677057', 'source_user_id': 793854134, 'source_user_id_str': '793854134'}, {'id': 1520564805475602400, 'id_str': '1520564805475602434', 'indices': [23, 46], 'media_url': 'http://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}}, 'source_status_id': 1520564817349677000, 'source_status_id_str': '1520564817349677057', 'source_user_id': 793854134, 'source_user_id_str': '793854134'}, {'id': 1520564805534290000, 'id_str': '1520564805534289920', 'indices': [23, 46], 'media_url': 'http://pbs.twimg.com/media/FRohomPVEAASBwR.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRohomPVEAASBwR.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}}, 'source_status_id': 1520564817349677000, 'source_status_id_str': '1520564817349677057', 'source_user_id': 793854134, 'source_user_id_str': '793854134'}, {'id': 1520564805609791500, 'id_str': '1520564805609791488', 'indices': [23, 46], 'media_url': 'http://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}, 'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}}, 'source_status_id': 1520564817349677000, 'source_status_id_str': '1520564817349677057', 'source_user_id': 793854134, 'source_user_id_str': '793854134'}]}, 'source': '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'retweeted_status': {'created_at': 'Sun May 01 00:44:37 +0000 2022', 'id': 1520564817349677000, 'id_str': '1520564817349677057', 'text': '夏の宝石 https://t.co/zSDV208rAG', 'truncated': False, 'extended_entities': {'media': [{'id': 1520564805353885700, 'id_str': '1520564805353885696', 'indices': [5, 28], 'media_url': 'http://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRoholkUUAA3rbM.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}}}, {'id': 1520564805475602400, 'id_str': '1520564805475602434', 'indices': [5, 28], 'media_url': 'http://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRohomBVkAIzaq-.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}}}, {'id': 1520564805534290000, 'id_str': '1520564805534289920', 'indices': [5, 28], 'media_url': 'http://pbs.twimg.com/media/FRohomPVEAASBwR.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRohomPVEAASBwR.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}}}, {'id': 1520564805609791500, 'id_str': '1520564805609791488', 'indices': [5, 28], 'media_url': 'http://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg', 'media_url_https': 'https://pbs.twimg.com/media/FRohomhVIAAQSrm.jpg', 'url': 'https://t.co/zSDV208rAG', 'display_url': 'pic.twitter.com/zSDV208rAG', 'expanded_url': 'https://twitter.com/Takano_Shiho/status/1520564817349677057/photo/1', 'type': 'photo', 'sizes': {'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'large': {'w': 2048, 'h': 1152, 'resize': 'fit'}, 'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}}}]}, 'source': '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 76, 'favorite_count': 589, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'ja'}, 'is_quote_status': False, 'retweet_count': 76, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'ja'}, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'F5F8FA', 'profile_background_image_url': None, 'profile_background_image_url_https': None, 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1511726514634588166/0L3xPaQ4_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1511726514634588166/0L3xPaQ4_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1346478670240616449/1650041603', 'profile_link_color': '1DA1F2', 'profile_sidebar_border_color': 'C0DEED', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': True, 'default_profile_image': False, 'following': None, 'follow_request_sent': None, 'notifications': None, 'translator_type': 'none', 'withheld_in_countries': []}

正しくパースされました。

トップページに戻る(=^・ω・^=)