JSON 转 YAML:空格缩进、Tab 与 ScannerError 边界
YAML 用缩进表达层级,Tab 与空格不是可以随意互换的排版字符。一个看似对齐的 Tab 可能触发解析器的 ScannerError 或同类缩进错误;具体错误名称、行列格式和文案取决于解析器。本文聚焦缩进边界,不把某个解析器的错误信息当成 YAML 标准。
一、问题概述:视觉对齐不代表 YAML 层级一致
下面两行在编辑器中可能看起来对齐,但 YAML 缩进需要由解析器按字符计算。Tab 混入 mapping 或 sequence 的缩进位置时,解析器无法确定当前节点属于哪一层。
二、最小复现:Tab 缩进与空格缩进
示例中的 \t 代表真实 Tab 字符;复制到文件时应确认不是两个可见反斜杠。正确版本只使用空格,并保持同一层级的缩进宽度一致。
const invalid = "user:\n\tname: Ada\n";
const valid = "user:\n name: Ada\n";
console.log(JSON.stringify(invalid)); // "user:\n\tname: Ada\n"
console.log(JSON.stringify(valid)); // "user:\n name: Ada\n"三、根因:YAML scanner 必须在缩进上下文中读取字符
解析器先判断当前行的缩进列,再决定它是 mapping、sequence 还是普通标量。Tab 会让列宽解释依赖规则,混合 Tab/space 还可能只在某个嵌套层级失败。错误可能被命名为 ScannerError、YAMLException 或其他解析器专属类型。
四、推荐方案:生成时只输出空格,解析时保留原始错误上下文
JSON→YAML 生成器应固定空格缩进,并在写文件后用目标解析器回读。遇到错误时保留行号、列号和原文片段,但不要把 PyYAML 的 ScannerError 文案硬编码成所有库都相同;不同解析器应通过适配层归一化错误类别。
五、完整代码:在调用 YAML parser 前定位缩进 Tab
下面的预检只报告出现在行首缩进区的 Tab,不替代 YAML parser。它能提前给出行号,最终语法判断仍由项目实际使用的解析器完成。
function indentationTabLines(source: string): number[] {
return source.split(/\r?\n/).flatMap((line, index) => {
const match = line.match(/^[ \t]+/);
return match?.[0].includes("\t") ? [index + 1] : [];
});
}
const source = "user:\n\tname: Ada\n";
const lines = indentationTabLines(source);
console.log(lines); // [2]六、常见错误方案
把 Tab 全局替换成固定数量空格可能改变原本的层级,尤其是混合缩进文件;只看编辑器渲染后的对齐也无法确认真实字符;捕获一个固定的 ScannerError 字符串,会让 js-yaml、PyYAML 或其他库的适配失效。
七、边界条件:字符串中的 Tab 与 block scalar
行首缩进 Tab 与 quoted string 或 block scalar 内容中的 Tab 不是同一个问题。预检应只关注缩进区,不能破坏需要保留的字符串内容。| 和 > block scalar 还会按缩进裁剪文本,修复时要保留其相对层级。
八、如何验证 YAML 修复
先检查原始文件的行首字符,再使用目标解析器读取修复后的文本。对 mapping、sequence、空值、引号字符串和 block scalar 做回读断言;记录解析器名称、错误类型和行列信息,避免把一个库的 ScannerError 误报成 YAML 的统一错误。
九、FAQ
问:YAML 标准是否完全禁止所有 Tab?答:至少不能用 Tab 表示缩进;字符串内容中的 Tab 是另一种语义,仍需按解析器规则处理。
问:为什么我的错误叫 ScannerError,别人的叫 YAMLException?答:这是解析器实现的错误类型差异,名称和文案不是跨库统一 API。
问:把 Tab 换成两个空格一定正确吗?答:不一定,必须结合相邻行和 block scalar 的层级重新解析。
十、总结
YAML 缩进错误的关键是实际字符和层级上下文,而不是编辑器中的视觉对齐。生成时使用一致空格,预检行首 Tab,最终交给目标 parser 验证;ScannerError 等名称和错误文案必须注明解析器差异。
来源与延伸阅读
技术审校所依据的规范与权威参考资料。
- YAML 1.2.2 Specification
YAML Language Development Team
- RFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format
RFC Editor
相关文章
JSON 转 YAML:yes/no、on/off 与布尔值隐式转换
区分 YAML 1.1、YAML 1.2 与具体解析器 schema 对 yes/no、on/off 的处理,说明何时会得到布尔值以及如何保留字符串。
最佳实践JSON/YAML 转换:Kubernetes 与 Docker Compose 的语义保留
区分 JSON↔YAML 的语法转换与 Kubernetes、Docker Compose 配置语义,分别检查顶层结构、类型、端口、环境变量和目标 schema。
踩坑避坑JSON 大整数精度丢失:Number 安全范围与解决方案
说明 JSON 大整数进入 JavaScript 后为什么会被舍入,演示 Number.MAX_SAFE_INTEGER 边界,并给出字符串契约、BigInt 转换和序列化的可验证方案。
继续阅读
可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。
打开关联工具