python json字串型別的value換行方案
阿新 • • 發佈:2020-09-21
按照標準json語法,字串型別的value是不能換行寫的.
例如,以下是錯誤的寫法
{
"key":"hello
world"
}
但是遇到了需要在json中寫程式碼與伺服器互動的情況,無奈只能這樣寫:
{
"key":"var a = 1\nvar b = 2\n var c=a+b"
}
程式碼行數少了還好,多了極其**,於是想辦法可以在json中換行寫程式碼.
嘗試1: json5
JSON5號稱"JSON for Humans",相比標準json主要特點如下:
- 字串value支援換行
- key可以不加""
- key和value可以使用''代替""
- 支援註釋
- 二進位制數值
栗子:
以下是一個合法的json5
{ // comments unquoted: 'and you can quote me on that', singleQuotes: 'I can use "double quotes" here', lineBreaks: "Look, Mom! \ No \\n's!", hexadecimal: 0xdecaf, leadingDecimalPoint: .8675309, andTrailing: 8675309., positiveSign: +1, trailingComma: 'in objects', andIn: ['arrays',], "backwardsCompatible": "with JSON", }
優點:現成
缺點:
-
換行需要用 \ \標識;
-
解析之後因為沒有了換行,程式碼無法執行,所以是達不到目的的;
{
"key":"var a = 1\
var b = 2\
var c=a+b"
}
解析之後的結果為
{
"key":"var a = 1var b = 2var c=a+b"
}
嘗試2: 編寫自己的json直譯器
- 優點: 可根據自己定義的規則解析資料
- 缺點: 成本高.
以下為用python實現的json直譯器,支援換行,目前沒有做完整的錯誤處理,請不要用於生產:
""" 遇到問題沒人解答?小編建立了一個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("\n", "\\n").replace("\r\n", "\\n") 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': '\n var code = 0\n code = 1\n '}, 'list': [1, 2, 3, 4]}
嘗試3: 全域性替換 \n 為 \n
優點:簡單粗暴
{
"key":"
var a = 1
var b = 2
var c=a+b"
}
替換之後的結果為
{
"key":"\nvar a = 1\nvar b = 2\n var c=a+b"
}
缺點:雖然寫的時候有換行,但是上傳到伺服器再查詢的時候只能看到\n,依然缺乏可讀性;
嘗試4(最終採用方案):
結合UI將json生成樹狀節點,將程式碼型別的value單獨顯示.
優點
- 難度一般
- 按常規方式解析json
- 上傳到伺服器再查詢的時候也能看到換行.