JSON压缩工具

把带缩进和换行的 JSON 文本压成单行最小形式,同时给出压缩前后字符数、UTF-8 字节数与压缩率,并列出压缩过程中会被改写的写法。

处理口径:JSON.stringify(JSON.parse(输入)),第二个参数不传。第三参数不传即无缩进,输出即最小形式。压缩是重新序列化而不是删空白,所以字符串值里的空格和换行会被原样保留。

压缩率—
原字符数—
压缩后字符数—
原 UTF-8 字节—
压缩后字节—

提示:这是多行文本框,Enter 用于换行,按 Ctrl / Cmd + Enter 触发压缩。下载的 .json 文件不带 BOM,避免服务端解析报错。

使用方法

  1. 把要压缩的 JSON 粘进左侧「输入 JSON 文本」。页面打开时已经放了一段带两空格缩进的订单服务配置(171 字符),可直接点「压缩」看效果。
  2. 点「压缩」或按 Ctrl / Cmd + Enter。这是多行输入框,单独按 Enter 只换行不触发。
  3. 右侧「压缩结果」立刻显示单行最小形式,同时上方五张卡片给出压缩率、原字符数、压缩后字符数和两边的 UTF-8 字节数。
  4. 确认无误后点「复制结果」贴到别处,或点「下载 JSON」存成 .json 文件(不带 BOM,可直接被后端 JSON.parse 读)。JSON压缩工具跑完一趟后还可以对结果再压一次,用于确认已经压到最小。
  5. 想还原成带缩进的可读版,请改用文末的格式化工具;本页只负责压缩方向。

这个JSON压缩工具能解决什么问题

接口返回、日志导出、配置下发这几条链路上的 JSON 通常带着两空格或四空格缩进,体积里塞的全是对解析毫无意义的空白。JSON压缩工具解决四件事:一是传输瘦身,示例里 171 字符的格式化配置压到 117 字符,省下 54 个字符、压缩率 31.6%,UTF-8 字节从 195 降到 141;二是统一出参,同一份数据无论写成两空格、四空格还是 Tab 缩进,压缩后得到的是逐字节相同的字符串,可以直接拿来做内容哈希或缓存键;三是找出冗余来源,对照表列出哪些写法在压缩过程中被改写,让你在源头就避免写出又长又易错的键名;四是暴露精度陷阱,12345678901234567890 会被解析成 12345678901234567000,压缩过程静默改了数值而没有任何警告。

本页只做压缩与体积统计。缩进美化、语法是否合法、键排序、两个 JSON 的差异对比,都不在这里做,请走文末分流。

原理和变量:为什么是 parse 再 stringify

核心只有一句:JSON.stringify(JSON.parse(输入))。两个参数都不传,走 ECMA-262 里 JSON.stringify(value) 的默认形式。

为什么不用正则删空白。正则分不清「语法空白」和「字符串里的空格」。对 {"s":" 空格 "} 做 replace(/\s+/g,'') 会把值里的两个空格一起删掉,输出 {"s":"空格"}——数据被改了,而且改得没有任何提示。走 parse 之后,语法空白在解析阶段就被丢弃,字符串值被完整保存在对象里,stringify 只负责按标准重新输出,值一个字符都不少。

第二个参数为什么必须空着。JSON.stringify 的第二参是 replacer,传 undefined 或不传都表示「保留全部键」。但如果误传一个数组,比如 JSON.stringify(o, ['a']),实测 {"a":1,"b":{"c":2}} 会变成 {"a":1},b 被整个丢掉;如果传函数 function (k, v) { return k === 'b' ? undefined : v },结果同样是 {"a":1}。这两处是真实的数据丢失,不是显示问题。

第三个参数为什么不给。第三参是缩进。实测传 null, 0 和不传等价;传 null, 2 就变回带两空格的格式化文本;传 null, 11 会被规范截到 10 个空格;传 null, -1 等同于 0;传字符串 ' ' 则用空格本身填充。压缩场景下唯一正确的选择就是不传。

字符数与字节数的区别。统计用两组口径:字符数取 String.length,按 UTF-16 码元计;字节数用 TextEncoder.encode() 的 byteLength。示例原文 171 字符但占 195 字节,差 24 字节来自「订单服务」等 8 个汉字——每个汉字在 UTF-8 里占 3 字节而只算 1 个字符。真正决定网络流量的是字节数,所以两个数都给你。

遵循的规范。JSON 语法由 ECMA-404 定义,交换格式由 RFC 8259 定义。本页不做任何超出这两份文档的宽松处理:尾逗号、单引号、注释、未加引号的键名一律报错,而不是猜测作者意图。

完整示例(数值仅作演示)

打开页面时输入框里是这段用两空格缩进的订单服务配置,JSON压缩工具输出的最小形式是:

{"name":"订单服务","version":"2.1.0","features":["限流","熔断","灰度发布"],"limits":{"qps":1200,"timeoutMs":3000},"enabled":true}

五张卡片分别是:压缩率 31.6%、原字符数 171、压缩后字符数 117、原 UTF-8 字节 195、压缩后字节 141。

把同一份数据改写成四空格缩进或 Tab 缩进(138 字符),压缩结果与上面逐字节相同;对已经压好的文本再压一遍,省下 0 个字符。这就是幂等性:压缩两次等于压缩一次,可以放心放在构建流程里反复跑。

体积构成上,示例里 features 这个键连值加引号共 31 字符,limits 子对象共 40 字符,而 enabled 只占 16 字符——长数组和嵌套对象才是压缩后的大头,缩进省下来的反而是零头。

输入范围与对照表

压缩过程会改写以下写法(前 12 行默认显示,点「加载更多改写规则」展开余下 2 行)。这一列是本页最该记住的部分:压缩不是纯删空白,有些值会被规范化。

原始写法压缩后发生了什么
{ "n" : 1.50 }{"n":1.5}小数末尾补零被去掉
{ "n" : 1.0 }{"n":1}整数值的 .0 被去掉
{ "n" : 1e3 }{"n":1000}科学计数法展开成整数
{ "n" : -0 }{"n":0}负零归零
{ "s" : "a\/b" }{"s":"a/b"}斜杠不必转义
{ "s" : "\u4e2d\u6587" }{"s":"中文"}Unicode 转义还原成汉字
{"\u4e2d":"x"}{"中":"x"}键名同样被还原
{ "b":2, "10":1, "1":2, "a":3 }{"1":2,"10":1,"b":2,"a":3}整数型键提前并按数值升序
{ "n" : 12345678901234567890 }{"n":12345678901234567000}超出安全整数,末位被改
{ "n" : 1e400 }{"n":null}溢出成 Infinity,JSON 无此值故写 null
{ "s" : " 空格 " }{"s":" 空格 "}值内空格原样保留
{ "s" : "line1\nline2" }{"s":"line1\nline2"}值内换行仍是转义符,不折行
{ "n" : 1.7976931348623157e308 }{"n":1.7976931348623157e+308}双精度最大值保留,指数补正为 e+308
{ "s" : "\u0009" }{"s":"\t"}控制字符用短转义表示

不同排版风格能省下多少,同一份 {"a":1,"b":2,"c":[1,2,3]} 为例:

原始排版原字符数压缩后省下
已是最小形式25250.0%
两空格缩进对象562555.4%
四空格缩进对象762567.1%
两空格缩进数组(8 元素)421759.5%
值含换行符的对象201525.0%

边界与精度

体积阈值分两档。输入超过 200 KB(204800 字节)时先在提示区说明「已进入大文本处理」,让用户知道会有短暂停顿;超过 2 MB(2097152 字节)直接拒绝并报错,提示改用命令行工具。参考量级:2 万条记录的数组格式化后约 1482 KB,本页压缩后约 818 KB、压缩率 44.8%,Node 侧实测耗时 9 毫秒——单页内跑得动,但再大就会让标签页卡住,所以设了硬上限。

最危险的边界是数字精度,不是体积。JSON 的数字字面量在 JSON.parse 里直接落成 IEEE 754 双精度数,安全整数上限是 253-1 = 9007199254740991。所以 12345678901234567890(订单号、雪花 ID 常见)会被解析成 12345678901234567000,末位被静默改掉,压缩过程不报任何错。长 ID 必须写成字符串,这是唯一可靠的做法。另一个方向的坑是 1e400:解析得到 Infinity,而 JSON 没有 Infinity,stringify 会写出 null。

BOM 绝不能带。实测 JSON.parse('\ufeff{"a":1}') 直接抛 SyntaxError: Unexpected token,因为 U+FEFF 不是 JSON 合法字符。所以本页「下载 JSON」写出的文件首字节是 7b({),不带 ef bb bf。本页的 CSV 导出是另一回事——那是给 Excel 看的表格,必须带 BOM,否则中文列名会乱码。

每条非法输入都指名报错。空输入报「输入框是空的」;带尾逗号 {"a":1,} 报「第 7 个字符附近多了逗号」;单引号 {'a':1} 报「JSON 的键和字符串都必须用双引号」;{"a":01} 报「第 6 个字符处的前导零不合法」;{"a":1} {"b":2} 报「第 8 个字符后有多余内容,一个 JSON 只能有一个顶层值」。全部给出位置和改法,不静默返回空串。

常见问题

压缩后数据变了,是不是工具出错?

要看变的部位。空白、缩进、换行被去掉是压缩的定义;而数字和转义序列被改写是 JSON.parse 的解析规则,属正常行为。最需要警惕的是大整数末位被改(12345678901234567890 → 12345678901234567000)和 1e400 变 null,这两种请把源数据里的数字改成字符串。

为什么不用正则删空白,那样更快也更简单?

因为正则分不清语法空白和字符串内容。{"s":" 空格 "} 会被删成 {"s":"空格"},数据被改且无提示。parse 阶段已经把语法空白丢掉,字符串值完整保存在对象里,再由 stringify 按标准输出,值一个字符都不会少。

压缩率 0% 是不是说明没生效?

说明输入本来就已经是最小形式了。实测对已压缩文本再压一次,省下 0 个字符,这是正常的幂等结果,不是故障。压缩率是「相对输入」算的,输入没冗余自然就是 0%。

为什么我的订单号压完末尾变了?

因为订单号是 19 到 20 位的整数,超出双精度安全整数上限 9007199254740991(253-1)。JSON.parse 用 Number 接住它,末几位被四舍五入。把订单号改成字符串 "12345678901234567890" 再压,值就原样保住了。

字符串里的换行会被折成一行吗?

不会。值里的换行在 JSON 里必须写成转义符 \n 两个字符,parse 读成实际换行字符,stringify 再转回 \n,所以输出永远是单行且数据无损。对照表里 {"s":"line1\nline2"} 这一行压缩前后完全一致。

下载的 .json 文件能不能直接上传到接口?

能。本页下载的文件不带 BOM,首字节就是 {。这正是本页和 CSV 导出的关键区别:CSV 是给 Excel 读的,必须带 BOM 才不乱码;JSON 交给机器读,带 BOM 反而会让 JSON.parse 抛 Unexpected token。

尾逗号、单引号、注释为什么不放过?

因为 JSON 语法由 ECMA-404 和 RFC 8259 严格定义,这三者都不合法。允许它们的是 JSON5 或 JSONC,那是另一套方言。本页的判断是「这段文本是不是合法 JSON」,不是「作者大概想表达什么」,所以一律报错并指出位置。

几 MB 的文件能处理吗?

超过 200 KB 会先提示,进入大文本处理;超过 2 MB 直接拒绝并建议改用命令行工具。参考量级是 2 万条记录约 1482 KB,压缩后 818 KB、实测 9 毫秒。单页能跑这个量级,再大就会让标签页无响应,所以设了硬阈值而不是让它卡死。

相关工具