按照标准json语法,字符串类型的value是不能换行写的.
例如,以下是错误的写法
<code class="language-python">{ "<a href="https://www.gaodaima.com/tag/key" title="查看更多关于key的文章" target="_blank">key</a>":"hello world" } </code>
www#gaodaima.com来源gaodaimacom搞#^代%!码&网搞代码
但是遇到了需要在json中写代码与服务器交互的情况,无奈只能这样写:
<code class="language-python">{ "key":"var a = 1 var b = 2 var c=a+b" } </code>
代码行数少了还好,多了极其**,于是想办法可以在json中换行写代码.
尝试1: json5
JSON5号称”JSON for Humans”,相比标准json主要特点如下:
- 字符串value支持换行
- key可以不加””
- key和value可以使用””代替””
- 支持注释
- 二进制数值
栗子:
以下是一个合法的json5
<code class="language-python">{ // comments unquoted: "and you can quote me on that", singleQuotes: "I can use "double quotes" here", lineBreaks: "Look, Mom! No "s!", hexadecimal: 0xdecaf, leadingDecimalPoint: .8675309, andTrailing: 8675309., positiveSign: +1, trailingComma: "in objects", andIn: ["arrays",], "backwardsCompatible": "with JSON", } </code>
优点:现成
缺点:
-
换行需要用 标识;
-
解析之后因为没有了换行,代码无法执行,所以是达不到目的的;
<code class="language-python">{ "key":"var a = 1 var b = 2 var c=a+b" } </code>
解析之后的结果为
<code class="language-python">{ "key":"var a = 1var b = 2var c=a+b" } </code>
尝试2: 编写自己的json解释器
- 优点: 可根据自己定义的规则解析数据
- 缺点: 成本高.
以下为用python实现的json解释器,支持换行,目前没有做完整的错误处理,请不要用于生产:
<code class="language-python">""" 遇到问题没人解答?小编创建了一个Python学习交流群:778463939 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书! Topic: 下降解析器 Desc : """ import re import collections # Token specification NUM = r"(?P<NUM>d+)" STR_D = r""(?P<STR_D>[^"]*?)"" STR_S = r"(?P<STR_S>".*?")" COLON = r"(?P<COLON>:)" COMMA = r"(?P<COMMA>,)" LLB = r"(?P<LLB>[)" RLB = r"(?P<RLB>])" LDB = r"(?P<LDB>{)" RDB = r"(?P<RDB>})" WS = r"(?P<WS>s+)" NULL = r"(?P<NULL>null)" FALSE = r"(?P<FALSE>false)" TRUE = r"(?P<TRUE>true)" master_pat = re.compile("|".join([NUM, STR_D, STR_S, LLB, RLB, LDB, RDB, COLON, COMMA, FALSE, TRUE, NULL, WS]), re.M | re.S) # Tokenizer Token = collections.namedtuple("Token", ["type", "value"]) def generate_tokens(text): scanner = master_pat.scanner(text) for m in iter(scanner.match, None): tok = Token(m.lastgroup, m.group()) if tok.type != "WS": yield tok def simple_join(text): li = [] for t in generate_tokens(text): res = t[1] if t[0] == "STR_S": res = t[1].replace(""", """) elif t[0].startswith("STR_"): res = t[1].replace(" ", " ").replace(" ", " ") li.append(str(res)) return "".join(li) class Evaluator: def __init__(self, text): self.text = text def parse(self): self.tokens = generate_tokens(self.text) self.nexttok = next(self.tokens, None) self._advance() return self._parse() def _advance(self): """Advance one token ahead""" self.tok, self.nexttok = self.nexttok, next(self.tokens, None) def _parse(self): if self.tok[0] == "LLB": return self.get_list() if self.tok[0] == "LDB": return self.get_dict() if self.tok[0].startswith("STR_"): return self.tok[1].strip(""") if self.tok[0] == "NUM": return int(self.tok[1]) if self.tok[0] == "NULL": return None if self.tok[0] == "FALSE": return False if self.tok[0] == "TRUE": return True raise Exception("未知token:{}".format(self.tok[1])) def get_dict(self): """ { 开头 中间内容必须为 k:v, 结尾必须为 } """ res = {} self._advance() # } if self.tok[0] == "RDB": return {} def parse_value(): if not self.tok[0].startswith("STR_"): raise Exception(f"KEY需是字符串形式,{self.tok[1]}") new_key = self._parse() self._advance() if self.tok[0] != "COLON": raise Exception("KEY和VALUE需用:分割") self._advance() res[new_key] = self._parse() self._advance() parse_value() while self.tok[0] == "COMMA": self._advance() parse_value() return res def get_list(self): res = [] self._advance() # } if self.tok[0] == "RLB": return [] def parse_value(): if self.tok[0] in ["NUM", "STR_D", "STR_S", "NULL", "FALSE", "TRUE"]: res.append(self._parse()) elif self.tok[0] == "LLB": res.append(self.get_list()) elif self.tok[0] == "LDB": res.append(self.get_dict()) parse_value() self._advance() while self.tok[0] == "COMMA": self._advance() parse_value() self._advance() return res if __name__ == "__main__": text = """ { "k1":1, "k2":"v2", "is_true":true, "is_none":null, "k2":"v2", "k3":{ "a1":"a1", "a2":"a2", "code":" var code = 0 code = 1 " }, "list":[1,2,3,4] } """ # test(text) e = Evaluator(text) res = e.parse() print(res) #{"k1": 1, "k2": "v2", "is_true": True, "is_none": None, "k3": {"a1": "a1", "a2": "a2", "code": " var code = 0 code = 1 "}, "list": [1, 2, 3, 4]} </code>
尝试3: 全局替换
为
优点:简单粗暴
<code class="language-python">{ "key":" var a = 1 var b = 2 var c=a+b" } </code>
替换之后的结果为
<code class="language-python">{ "key":" var a = 1 var b = 2 var c=a+b" } </code>
缺点:虽然写的时候有换行,但是上传到服务器再查询的时候只能看到
,依然缺乏可读性;
尝试4(最终采用方案):
结合UI将json生成树状节点,将代码类型的value单独显示.
优点
- 难度一般
- 按常规方式解析json
- 上传到服务器再查询的时候也能看到换行.