前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JSON格式化

JSON格式化

作者头像
江湖安得便相忘
发布2019-08-21 11:14:09
3.6K0
发布2019-08-21 11:14:09
举报

我个人主要是做一些后端的工作,比如php、python、c之类的,c比较少,最主要的是php,不过我非常喜欢js,所以经常会愿意去写一些小玩意自娱自乐。

今天在测试接口的时候,使用原生js的XMLHttpRequest去请求,直接使用document….innerHTML输出到页面,因为没有浏览器的json格式化没有生效,所以接口响应的json数据就看起来很不舒服。

于是乎,我就想起了为啥我自己不能实现一个,应该不是很难吧。

我仔细思考了一下,这玩意不就是遇到大括号、中括号和中括号就换行吗,每行还有个缩进,人家再高级一点的还有颜色,折叠功能、缩进对齐线之类的,于是我觉得一步一步来,先把格式化和颜色实现出来,后面的折叠、动画和缩进对齐线再慢慢做。

电影有句话说的好啊:“步子迈大了,咔,容易扯着蛋”。

扯了这老些没用的,下面开始我的正经思路:

合法的JSON字符串是一个单行字符串,边界符号是“{} []”,键值对之间是以英文逗号“,”作为分隔,键和值之间是用英文冒号“:”进行分隔。JSON内的字符串必须以双引号包括在外侧,数字类型或布尔类型可以不使用双引号包括。逗号分隔符的后面必须至少存在一个键值对(即末尾的键值对的后面不能有逗号分隔符了,这里的逗号指的是键值对分隔符,而不是指值内的逗号字符串)。

看看别人优秀的是什么样子的。

从某平台的json格式化服务截取

可以发现在“{, [”的后面都会有一个换行,每个键值对的后面都有一个换行,在符号“], 和 }, ”的后面都会有一个换行。

而且格式化后的JSON是有“结构区块”的,从缩进来区分不同的结构块,这一点有点像python,不过这有点牵强,格式化这样做的目的是为了能够很清晰的查看JSON的结构,与python的目的是有本质的区别的。

从截图来看,只要遇到一个“{ 或 [”,就要出现缩进,而且可以看出,缩进是随着遇到的个数增加的,这是成正比啊。而且只要遇到“]或}”,缩进就要少一个。

说到这里是不是就有感觉了,缩进就是在匹配括号啊,这匹配括号在逆波兰式里的操作啊,不就是基础的数据结构“栈”吗。

那我对整个字符串进行遍历判断是不就能做到了,那有了思路就可以动手了,能动手我就不在这里扯?了。

代码语言:javascript
复制
<!-- 这里在页面放一个pre标签,让输入的结构按照我们需要的形式展现 -->
<pre id="json"></pre>

假设我有一个jsonStr,我想要格式化它。

代码语言:javascript
复制
var jsonStr = '{"state":{"code":0,"success":true,"ok":1},"body":[{"count":2394,"dbName":"star_all"},{"count":133,"dbName":"star"},{"count":7,"dbName":"zy"},{"count":1,"dbName":"gordon_test"}]}';
代码语言:javascript
复制
function format(str){
    var stack = []; //栈-用于括号匹配
    var tmpStr = '';    //新格式化JSON字符串
    var len = str.length;   //原始JSON长度

    //遍历每一个字符
    for (let i = 0; i < len; i++) {

        //当遇到结构块起始结构
        if (str[i] == '{' || str[i] === '[') {

            //起始结构后面直接换行  
            tmpStr += str[i] + "\n";

            //入栈
            stack.push(str[i]);
            
            //这里的意思是结构块起始的下一行开始就会有一个缩进,缩进量与遇到的结构块起始符个数成正比1:1
            tmpStr += "\t".repeat(stack.length);
        } 
        //当遇到结构块结束符
        else if (str[i] == ']' || str[i] === '}') {

            //因为本身JSON格式是固定的,所以括号一定是成对的,这里先不考虑错误的json数据
            //遇到结束符就退栈,
            stack.pop();

            //结束符本身输出到下一行,并减少一个缩进
            tmpStr += "\n"+"\t".repeat(stack.length) + str[i];
        } 
        //当遇到逗号的时候
        else if (str[i] == ',') {
            //逗号后方直接换行,以及下一行的缩进处理
            tmpStr += str[i] + "\n" + "\t".repeat(stack.length);
        } 
        else {
            //其他字符直接复制
            tmpStr += str[i];
        }
    }
    return tmpStr;
}

返回的数据放到<pre>标签内

代码语言:javascript
复制
document.querySelector('#json').innerHTML = format(jsonStr);

输出的效果如下图

制表符\t稍微有点远,当然使用4个 也可以,别纠结~

这黑白色的不美观,那就给上个色呗,看看人家的,括号一个颜色,键值对一个颜色,值一个颜色,我不能抄它的,我觉得字符串,数字、布尔都分别用一种颜色就行,这个实现就都能实现了。

那既然需要分开使用不同的颜色,那么必然就涉及CSS了,每个结构就得有HTML结构了,我直接用正则是不是就解决了。

先写个CSS样式把

代码语言:javascript
复制
.bold{
    font-weight: 900;
}
.string-color {
    color: darkred;
}
.token {
    color: darkgreen;
}
.number {
    color: green;
}
.bool {
    color: orange;
}
代码语言:javascript
复制
//使用捕获,匹配全部的边界符号,class使用token
tmpStr = tmpStr.replace(/([\{\[\]\}])/g, '<span class="token bold">$1</span>');

//使用零宽断言和捕获,匹配全部的两侧是双引号的字符串,class使用string
tmpStr = tmpStr.replace(/(?<=\")(\w+)(?=\")/g, '<span class="string bold">$1</span>');

//使用零宽断言,匹配全部的前面位置是冒号,后面是逗号或换行的数字类型值
tmpStr = tmpStr.replace(/(?<=\:)(\d+)(?=[\,\n])/g, '<span class="number bold">$1</span>');

//同理匹配布尔,
tmpStr = tmpStr.replace(/(?<=\:)(true|false)(?=[\,\n])/g, '<span class="bool bold">$1</span>');

零宽断言就是匹配一个位置,分负向零宽断言和正向零宽断言,不知道的可以搜索一下。

效果还行

到这里就初步完成了一个还算能入眼的基础JSON格式化小方法。后续再加个闪电爆炸的特效,下次再分享~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 可回收BUG 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档