JSON 格式化 / 校验
粘进来就能按 2 个空格、4 个空格或 Tab 重新排版,也可以一键压成一行;如果它根本不是合法 JSON,这里会给出出错的行号和列号,以及人话的原因。所有解析都在你的浏览器里完成,粘进来的内容不会上传。
你在上面输入的内容不会发给我们:解析、格式化、压缩全部在这个页面里完成。详见 隐私说明。
怎么用
- 把 JSON 粘进框里。接口返回、配置文件、日志片段、手写的内容都行。短内容会边打字边校验; 长内容留到你按按钮时再算 —— 每敲一个字就重新解析一份大文件,输入会明显发卡。
- 选缩进,点「格式化」。2 个空格是最常见的约定,也是 diff 视图期望的形式;4 个空格在 Java、.NET 项目里常见;Tab 让文件更小,而且每个读者可以用自己的宽度显示。想反着来就点「压缩成一行」: 去掉全部多余空白,只留一行。
- 看结果,然后复制或下载。下面的统计告诉你解析器实际看到了什么:顶层是什么类型、所有对象里 一共多少个键、结构有多深、按字符和 UTF-8 字节各有多大。
如果不是合法 JSON,你不会得到任何结果,只会得到出错的行、列和一句人话原因。这是刻意的: 半个格式化结果看起来像是成功了。
报错,但不替你修
不少格式化工具会悄悄把问题抹平:删掉多出来的逗号、把单引号换成双引号、删掉注释。这样得到的文件在你的 编辑器里看着完全正常,发给你要发给的那个程序却照样失败 —— 而且真正的问题被藏起来了:这段文字本来就不是 JSON。
这个工具不改写你的输入。解析失败时你会拿到位置和原因,而"这些数据本来想表达什么"这件事留给你判断。 下面这七类写法覆盖了绝大多数情况:
| 你粘进来的写法 | JSON 要求 | 通常来自哪里 |
|---|---|---|
{"a": 1,} | } 或 ] 前面不能有逗号 | 手改过的配置、JS 对象字面量 |
{'a': 1} | 键和字符串都用双引号 | Python 字典、JavaScript 字面量 |
{a: 1} | 键必须是加引号的字符串 | JS 简写、YAML |
// 说明 | JSON 没有任何注释语法 | JSONC、tsconfig、文档里的示例 |
NaN、Infinity、undefined | 只有数字、字符串、布尔、null、数组、对象 | 把 JS 的值直接序列化出来 |
01、0x1F、+5 | 不能有前导零、十六进制、正号 | 从代码里复制的数字 |
{"a": 1 "b": 2} | 两项之间要有逗号 | 手改、或者粘贴被截断 |
其中两类值得多说一句,因为报错的位置都不是你真正写错的那个字符:少了逗号时报的是"本该有逗号的那个 位置",括号没闭合时报在文本结束之后 —— 文件就是在这里断掉的。这两种情况下位置都是对的,它标的是解析器 无法继续的那一刻。
行号和列号是怎么定出来的
同一个错误,三个浏览器引擎的说法完全不同:Chrome 报字符位置外加行列,Firefox 只报行列,Safari 常常 什么都不报。所以这个工具从不照抄那句报错 —— 引擎给了字符位置就用它,没给就用自己那个严格扫描器逐字 定位,再按你粘进来的原文算出行列。具体有三条规则:
- 行按换行符数。内容相同的 CRLF 文件和 LF 文件会报出同一行同一列 —— 否则同一份文档在 Windows 和 macOS 上看起来会是两个不同的错误。
- 列按字符数,不按字节也不按 UTF-16 码元。一个汉字、一个 emoji 都算一列,跟编辑器里看到的一致。
- 都定位不到时明说不知道。不会为了显得权威而印一个编出来的位置。
这件事比听上去重要:位置是语法错误里唯一能照着动手的信息,没有它,你就只能在一份四千行的数据里用眼睛找。
有两种情况,格式化会改变你的数据
格式化本该是无损的,对格式良好的 JSON 也确实如此。只有两个例外,本工具都会明确报出来, 而不是让你以后自己发现。
重复的键
JSON 的文法允许一个对象里出现两次同一个键,但没规定这意味着什么。包括你浏览器在内的每个
JavaScript 引擎都保留最后一个值、丢掉前面的。所以 {"a": 1, "a": 2} 格式化后是
{"a": 2},第一个值没有了。本工具会把发现重复的路径列出来 —— 这正是"重新排版"与
"改了文件"之间的区别。
超出精确范围的整数
JavaScript 只有一种数字类型:64 位双精度浮点。能精确表示的整数上限是 9007199254740991(253 − 1)。
20 位的订单号、雪花 ID 在被读到之前就已经被四舍五入过:12345678901234567890 会变成
12345678901234567000。本工具会数出超过这个范围的整数并逐个点名,因为一个被四舍五入过的
标识,出事的地方往往不是编辑器而是几天后的线上。
这两种情况的解法都在你那边:如果本来想留的是前面那个重复值,或者这个 ID 必须一字不差,
请改用保留数字字面量的工具 —— 例如命令行的 jq,或者把大数字当字符串读的解析器。
大文件、长粘贴,与浏览器这一个标签页
解析和重新序列化跟页面绘制跑在同一个线程上,所以过了某个量级,格式化工具带来的就不再是方便, 而是一个看起来像卡死的标签页。下面三条限制都是从这件事推出来的,而且都是明说而不是悄悄执行:
- 200 万个字符是硬上限。超过就直接拒绝并解释原因,因为那种卡顿和崩溃在用户看来没有区别。
- 超过 30 万个字符的粘贴会先显示"正在处理",计算放到下一个事件循环节拍里执行, 这样界面先画出来再干活。低于这个量级的工作在一帧内就结束了,提示只会一闪而过,反而干扰。
- 嵌套极深的 JSON可能合法却写不出来:浏览器原生的序列化是递归的,大约五千层就会把调用栈用尽。 本工具会识别这种情况并告诉你"数据没问题,是工具的限制"—— 这才是诚实的说法,也正是这种时候该换命令行。
这些限制都不影响正确性:400KB 的数据和 4 字节的数据,格式化的准确程度完全一样。
有什么东西离开了这个页面
没有。不上传、不请求我们的服务器、不给你的数据挂任何统计事件、不做任何存储:这一页只引用了一个 小模块的纯函数,之后全在本地算。关掉标签页,你粘进来的 JSON 就没了。
但这不等于任何内容都可以往里粘。如果你用的是共用或受管理的电脑,剪贴板、下载目录和浏览器自己的内存 都不在这个页面能管的范围内;而且任何还在生效的密钥,粘到哪里都还是有效的。这个工具只负责告诉你它看到了 什么,你带在身上的东西还得你自己负责。
常见问题
- 为什么这段 JSON 在 JavaScript 里能用,到这里就报错?
- 因为 JavaScript 的对象字面量不是 JSON。JS 允许键不加引号、允许单引号、允许最后多一个逗号、允许 // 注释、允许 NaN 和 undefined —— JSON 一个都不允许,JSON.parse 全部拒绝。本工具按 JSON 的规矩来:多一个逗号就报到它的行列位置,不会替你删掉。如果这段文字是从 .js 文件里拷出来的,这个差别通常就是全部原因。
- 它报的行号列号可信吗?
- 行号列号是根据出错字符的偏移量算出来的,不是照抄浏览器的报错文字 —— 三个引擎对同一个错误的说法完全不同:Chrome 给字符位置,Firefox 只给行列,Safari 常常什么都不给。浏览器没给位置时,本工具用自己的严格扫描器定位。行按换行符数,CRLF 与 LF 得到同样的行列,中文和 emoji 各算一列,所以在编辑器里对着数能对上。两边都定位不到时,它会直接说位置未知,不会编一个数字出来。
- 格式化和校验是一回事吗?
- 不是,分开看更有用。校验只回答一个问题:这段文本是不是合法 JSON;格式化是在"它是合法的"这个前提下重新排版。本工具一定先解析再输出,所以看到格式化结果就等于确认了解析通过。也正因为这个顺序,这里没有"自动修复"按钮:把多出来的逗号悄悄删掉,只会让本工具认可一份你真正要发给别人的程序仍然会拒绝的文本。
- 重复的键会怎么处理?
- 保留最后一个,这是所有 JavaScript 引擎里 JSON.parse 的行为,属于语言规则,不是这里的开关。本工具不假装没有这回事:发现重复键就会把它们列出来,让你判断重复是不是你想要的。如果本来想留的是前面那个值,那么"格式化"这一步其实已经改动了你的数据 —— 那条提示是唯一会告诉你这件事的地方。
- 为什么大整数 ID 格式化之后就变了?
- 因为 JavaScript 只有一种数字类型:64 位双精度浮点,能精确表示的整数上限是 9007199254740991。像 12345678901234567890 这样的订单号,一进解析就已经变成 12345678901234567000。本工具会数出超出这个范围的整数并单独提示,而不是把一个四舍五入过的值当成结果交给你。如果整份数据都是靠大整数 ID 串起来的,请改用能保留数字字面量的工具。
- 能处理多大的文件?
- 上限 200 万个字符(大约 2MB 文本)。超过就直接拒绝并说明原因,而不是让标签页卡住 —— 解析和重新序列化跟页面绘制跑在同一个线程上。超过 30 万个字符的输入会先显示"正在处理",让你知道它确实动了。文件比上限还大就切开处理,或者干脆用命令行工具,那种体量本来也更适合命令行。
不含任何数据。这一页没有 schema、没有示例数据表、没有查询表 —— 它显示的每一个字符都 来自你粘进来的内容。它唯一的判据就是 JSON 文法本身。