1. 程式人生 > >Python 讀取帶有註釋的JSON檔案

Python 讀取帶有註釋的JSON檔案

在讀取json檔案時,有時會遇到檔案中含有註釋時,會報

Expecting property name: line 12 column 3 (char 268)

意思即在檔案12列3行處存在不符合JSON格式的字元,也就是註釋。

要想解析這個JSON檔案,必須要去除檔案中的註釋,在node.js中有專門去除註釋的第三方包 strip-json-comments,但很可惜在python中不存在這樣的包。

在網上找到了一份程式碼

import json
import re
# Regular expression for comments
comment_re = re.compile(
    '(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?'
, re.DOTALL | re.MULTILINE ) def parse_json(filename): """ Parse a JSON file First remove comments and then use the json module package Comments look like : // ... or /* ... */ """ with open(filename) as f: content = ''
.join(f.readlines()) ## Looking for comments match = comment_re.search(content) while match: # single line comment content = content[:match.start()] + content[match.end():] match = comment_re.search(content) print content # Return json file
return json.loads(content)

可以去除形如

// ....
/*
....
*/

的註釋,但在去除第一種註釋時,可能會有誤傷,比如說JSON檔案中有這樣一個鍵值隊

"url": "http://127.0.0.1:16666",

http: 後面的 //127.0.0.1:16666”則會被去除,看來還是得自己寫一套

# 讀取帶註釋 // /* */ 的json檔案
    def parse_json(self,filename):
        """ Parse a JSON file
            First remove comments and then use the json module package
            Comments look like :
                // ...
            or
                /*
                ...
                */
        """
        res = []
        f = open(filename)
        all_lines = f.readlines()
        #去除形如 // 但不包括 http:// ip_addr 的註釋
        for line in all_lines:
            l = self.strip_comment(line)
            res.append(l)
        result = []
        comment = False
        #去除形如 /* */的註釋
        for l in res:
            if l.find("/*") != -1:
                comment = True
            if not comment:
                result.append(l)
            if l.find("*/") != -1:
                comment = False
        #若直接使用 json.loads(str(res)) 會報 "ValueError: No JSON object could be decoded"
        str_res = ""
        for i in result:
            str_res += i
        return json.loads(str_res)
    def strip_comment(self,line):
        #匹配IP地址的正則表示式
        ip_re = re.compile('[0-9]+(?:\.[0-9]+){0,3}')
        index = line.find("//")
        if index == -1 :
            return line
        line_str = line[index + ]
        if ip_re.search(line_str):
            return line[:index+16] + self.strip_comment(line[index+17:])
        else:
            return line[:index] + self.strip_comment(line_str)

這份程式碼解決了上述問題。