开发者工具 · JSON 格式化程序和验证程序
破坏 JSON 的不可见字符:BOM、智能引号和 NBSP
· 工作原理
json 开发人员工作流程 验证
当验证器在第一个字符处报告错误并且文件看起来很完美时,通常会归咎于不可见的字符。这篇文章解释了字节顺序标记、印刷引号和不间断空格,以及如何报告每一项。
行 1,列 1,没有看到任何错误
行 1,列 1,没有什么问题 — JSON 文档可以以占据实际位置但渲染时没有可见字形的字符开头。然后,左大括号出现在第一个,即使其前面有字节顺序标记或零宽度字符。严格的解析器在到达 `{` 之前会遇到该隐藏代码点,因此报告第一列是准确的而不是模糊的。显示和字符序列只是讲述不同的故事。
不要仅仅因为插入符号出现在它旁边而删除看起来正确的大括号。检查报告偏移处的代码点,启用可见空白或切换到十六进制视图。 ToolAcre 在解析之前不会默默地删除前导 BOM,并且其扫描器会报告第一个意外字符。
UTF-8 字节顺序标记
UTF-8 字节顺序标记 — 字节序列 EF BB BF 在文件开头解码为 U+FEFF。 UTF-8 中的字节顺序并不含糊,因此该标记是不必要的,但某些编辑器和导出工具仍然将其添加为编码签名。 RFC 8259 表示 JSON 生成器不得将 BOM 添加到网络 JSON 中,尽管解析器可能会选择忽略一个 BOM 以实现互操作性。不能跨工具假设这种容忍度。
在 JavaScript 字符串中,BOM 是一个字符,尽管其 UTF-8 表示使用三个字节。 ToolAcre 报告字符串字符中的位置,因此前导标记出现在行 1、列 1 处。配置编辑器以在分发文件之前保存不带 BOM 的 UTF-8 或删除 U+FEFF。
来自文字处理器的智能引用
来自文字处理程序的智能引号 — 印刷的开始和结束标记在散文中看起来很优美,但 JSON 只将 ASCII 引号 U+0022 识别为字符串分隔符。 U+201C 和 U+201D 是普通的 Unicode 字符。在字符串之外,它们不能以属性名称或值开头,因此验证器会报告智能引号本身。聊天、电子邮件或文档编辑器中的自动更正通常会在 JSON 最初有效后引入更改。
将分隔符替换为直双引号,然后检查属于该值的撇号和引号。作为正确分隔的 JSON 字符串内的内容,大引号是完全合法的,例如 `"She said “go”"`;仅当要求执行分隔符的语法工作时,它们才会失败。
不间断空格和零宽度字符
不间断空格和零宽度字符 — JSON 空白是一个故意简短的列表:普通空格 U+0020、制表符 U+0009、换行符 U+000A 和回车符 U+000D。不间断空格 U+00A0 可能看起来与冒号和值之间的普通空格相同,但它不在该列表中。零宽度空格 U+200B 根本不显示任何内容,但它仍然是带引号的字符串之外的意外字符。
网页使用不间断空格将单词保持在一起,消息传递系统可能会插入零宽度字符以进行换行或脚本处理。复制格式化的片段可以将它们带入配置中。根据报告的偏移量,用普通空格替换结构 NBSP 字符并删除不需要的零宽度字符。
工作示例:从聊天消息复制的配置
工作示例:从聊天消息复制的配置 - 假设可见文本类似于 `{"mode": "safe"}`,但验证在开始时失败。六角视图显示支架前的 EF BB BF。删除该 BOM 会将下一个报告推进到 `mode` 之前的报价,实际上是 U+201C。将两个智能分隔符替换为 U+0022 然后在冒号和值之间公开 U+00A0。
将该结构不间断空格更改为 U+0020 并再次验证。现在可以正常格式化接受的结果。这个序列说明了为什么仅修复屏幕显示的内容是不可靠的:几个不可见或相似的字符可能占据不同的语法位置。按照每一行和每一列,识别实际的代码点,进行有意的替换并重新运行验证。
如何看到看不见的东西
如何查看不可见的内容 — 启用编辑器的渲染空白选项来区分制表符和空格并显示不寻常的间隙,然后使用 Unicode 检查器或十六进制视图查看看起来仍然相同的字符。 UTF-8 BOM 显示为 EF BB BF,不间断空格显示为 C2 A0,零宽度空格显示为 E2 80 8B。智能开盘价和收盘价显示为 E2 80 9C 和 E2 80 9D。
在计数之前匹配诊断的坐标系。 ToolAcre 扫描 JavaScript 字符串,因此其列计数 UTF-16 代码单元,而不是 UTF-8 字节。因此,面向字节的十六进制编辑器可以在非 ASCII 字符之后显示更大的数字偏移量。使用报告的行缩小搜索范围,检查相邻的代码点并仅根据需要进行翻译。
这不包括什么
这不包括什么 - mojibake 例如 `café` 可以是完全有效的 JSON。解析器看到普通的字符串字符序列,并且没有证据表明 UTF-8 字节之前已解码为另一种编码。同样,带引号的值内的不间断空格或零宽度字符在语法上也是有效的。验证捕获违反 JSON 语法的字符;它无法决定有效的 Unicode 内容是否符合作者的意图。
使用原始编码和错误编码的知识修复字节变为文本边界处的编码损坏。不要重复编码和解码 JSON 字符串,直到它看起来更好,因为这可能会损坏已经正确的字符。应用程序级规范化也是一个单独的决定:视觉上相同的 Unicode 序列可能会进行不同的比较,但仍保持有效。
要点:即使线路看起来很干净,也要相信报告的列
要点:即使行看起来很干净,也要相信报告的列 - 不可见的字符和看起来相似的标点符号仍然占据源中的精确位置。前导 BOM、卷曲分隔符、不间断空格或零宽度标记可以阻止解析器到达显示正确的大括号或引号。显示空白,检查代码点或字节并替换其身份与其语法角色冲突的字符,而不是随机编辑附近可见的 JSON 。
请记住,位置可能会计算字符,而十六进制工具会计算编码字节,因此请比较周围的文本,而不是期望每个偏移量都匹配。仅删除文档边界处的 BOM,将智能分隔符转换为 U+0022 并替换无效的结构间距,而不删除字符串内的合法 Unicode。