likes
comments
collection
share

开发个 json 格式化工具 兼容常见异常格式(不带引号的key 末尾多余逗号)

作者站长头像
站长
· 阅读数 33

背景

我经常需要格式化json,有时候是需要把它变得易读,有时候是需要把它压缩。

我常用网上的在线工具,但是有些工具很卡、有些工具有广告、有些工具甚至有泄露数据的安全风险。所以我自己动手开发了一个工具。

而且,我只想用纯 html js css 实现,不依赖任何库,尽可能减少它的体积。

开发个 json 格式化工具 兼容常见异常格式(不带引号的key 末尾多余逗号)

理想效果

3种格式化模式

考虑到我的日常使用主要是2种场景:

  1. 易读,易修改。
  2. 压缩json(删除多余换行符和空格)。

所以我放了单选按钮在开头。包括3个:

  • 2空格,基本类型数组不换行
  • 2空格,基本类型数组和基本类型对象不换行
  • 不换行,不空格

2空格,基本类型数组不换行

其中第一个是默认选项,因为「易读」确实是最常见的诉求。而且我经常遇到这种数据:

{
  "a": [
    1,
    2
  ],
  "b": [
    2,
    3
  ]
}

这样的话,数组会显得非常「不易读」。数组明明一行就可以展示完,却换了很多行。

所以,我在默认选项中设置了「基本类型数组不换行」。

2空格,基本类型数组和基本类型对象不换行

此外,这种格式也很常见:

{
  "a": {"x": 1, "y": 2},
  "b": {"x": 3, "y": 34}
}

如果每个x和每个y都换行,其实也不太方便观察。所以我第二个选项设置了「基本类型数组和基本类型对象不换行」。此时这种情况的表现会更直观。

不换行,不空格

另外,如果你希望删除多余换行符和空格,可以用第三个选项。

格式容错

我们输入json时,很多时候容易有些失误,包括:

  • key 没带引号
  • key 带的是单引号
  • 最后一个项目多了个逗号

这些都会导致 json 格式非法。但其实他们完全可以被正确解析。所以我希望兼容这些错误。

使用地址 & 源码

使用地址:tool.hullqin.cn/json-format…

源码:github.com/HullQin

开发难点

  1. 如何兼容错误。
  2. 如何实现「基本类型的数组不换行」。

兼容错误

我采用了简单的方案:eval,直接把它当作JS对象来执行。其实json数据本身也可以直接当做JS语法来执行。因此用eval既可以处理合法json、也可以处理js对象。非常完美的兼容了json格式错误。

核心逻辑如下:

let data;
eval('data = ' + event.target.value.trim());

如何实现:基本类型数组不换行、基本类型对象不换行

如果直接使用JSON.stringify,像这样:

JSON.stringify(data, null, 2);

那么数组所有项目都会被换行,所以不能这么简单写。

我们需要手写一个stringify,但是针对基本类型数组或对象,特殊处理。我写完了,如下:

const getLevelSpaces = (level) => Array(level * 2).fill(' ').join('');
const isBasicType = (item) => item === null || typeof item !== 'object';
const stringify = (obj, skipBasicObj, level = 0) => {
  if (obj === null || obj === undefined) return 'null';
  if (typeof obj !== 'object') return obj.toString();
  if (Array.isArray(obj)) {
    if (obj.every(item => isBasicType(item))) return '[' + obj.join(', ') + ']';
    return '[\n' + getLevelSpaces(level + 1) + obj.map(item => stringify(item, skipBasicObj, level + 1)).join(',\n' + getLevelSpaces(level + 1)) + '\n' + getLevelSpaces(level) + ']';
  }
  const entries = Object.entries(obj).filter(value => value[1] !== undefined);
  if (entries.length === 0) return '{}';
  if (skipBasicObj && entries.every(value => isBasicType(value[1]))) {
    return '{' + entries.map(value => '"' + value[0] + '": ' + stringify(value[1], skipBasicObj)).join(', ') + '}';
  }
  return '{\n' + getLevelSpaces(level + 1) + entries.map(value => '"' + value[0] + '": ' + stringify(value[1], skipBasicObj, level + 1)).join(',\n' + getLevelSpaces(level + 1)) + '\n' + getLevelSpaces(level) + '}';
};

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,联系我,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋象棋等游戏,不收费无广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》《极致用户体验》

转载自:https://juejin.cn/post/7159222601707946015
评论
请登录