ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

yq to_number 算子详解:字符串与数值类型的安全转换实战

yq to_number 算子详解:字符串与数值类型的安全转换实战 yq to_number 算子详解字符串与数值类型的安全转换实战【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq本文以 yq 官方算子文档 pkg/yqlib/doc/operators/to_number.md 为骨架结合仓库内 operator_to_number.go 的实现源码与 operator_to_number_test.go 的测试用例系统讲解to_number算子的解析策略、边界行为、错误处理与 jq 兼容写法。读完本文你将掌握如何用 yq 把引号包裹的数字字符串安全转换为真正的 int/float 节点理解先 int 后 float的解析顺序并能在管道、条件过滤与排序等真实场景中正确使用该算子。算子定位把看起来是数字的输入变成真正的数字to_number是 yq 中用于类型转换的算子。它解析输入值并尝试将其转换为数字yq 会先尝试将值解析为 int失败后再尝试解析为 float对于本身就是 int 或 float 的节点则原样保留不做任何改动。在 yq 的数据模型中每个节点都带有一个 YAML tag如!!int、!!float、!!str、!!null。to_number的本质就是重新判定节点的数字标签把字符串值3变成带!!int标签的数字节点3把3.1变成带!!float标签的3.1。这一点可以在测试期望输出中直观看到D0, P[0], (!!int)::3 D0, P[1], (!!float)::3.1 D0, P[2], (!!float)::-1e3来源operator_to_number_test.go基础用法一把字符串转换为数字假设存在一个sample.yml文件内容为三个被引号包裹的数字字符串- 3 - 3.1 - -1e3执行管道表达式yq .[] | to_number sample.yml输出结果为3 3.1 -1e3可以看到3被识别为整数输出33.1与-1e3科学计数法被识别为浮点数输出3.1与-1e3。这里.[]负责遍历数组的每个元素to_number对每个元素分别执行转换。基础用法二数字本身保持不变当输入已经是数字时to_number不会产生任何改变。给定如下sample.yml- 3 - 3.1 - -1e3执行同样的命令yq .[] | to_number sample.yml输出保持原样3 3.1 -1e3这正是算子文档强调的Values that already ints or floats will be left alone已具备!!int或!!float标签的节点直接透传不做二次解析。解析策略先尝试 int失败再尝试 floatto_number的先 int 后 float策略并非玄学而是由源码中的tryConvertToNumber函数明确实现的operator_to_number.gofunc tryConvertToNumber(value string) (string, bool) { // try an int first _, _, err : parseInt64(value) if err nil { return !!int, true } // try float _, floatErr : strconv.ParseFloat(value, 64) if floatErr nil { return !!float, true } return , false }转换流程分三步先走整数路径调用parseInt64尝试解析成功则返回 tag!!int整数失败走浮点路径调用 Go 标准库strconv.ParseFloat(value, 64)成功则返回 tag!!float两者都失败返回converted false交由上层报错。整数解析的 YAML 特性支持值得深入说明的是parseInt64并不是简单的十进制ParseInt它额外支持了 YAML 数字特有的书写形式lib.go下划线分隔符1_000这类带下划线的写法会先移除下划线再解析十六进制前缀0x/0X前缀按 base 16 解析如0xFF可转换为255八进制前缀0o前缀按 base 8 解析正负号剥离解析前会把开头的/-符号剥离开再交给ParseInt避免符号干扰前缀检测。这意味着to_number对0xFF、0o17、1_000_000这类字符串同样能完成整数转换并不局限于纯十进制写法。而浮点路径则完全遵循 Go 的ParseFloat语义因此-1e3科学计数法、3.1都会被归入!!float。错误处理什么情况下会转换失败to_number的失败处理分两类对应源码中两个不同的错误分支operator_to_number.go。1. 节点不是标量Scalar类型当输入节点是映射Map或序列Sequence等复合节点时直接报错cannot convert node at path 路径 of tag tag to number从源码看该分支在循环开头即拦截非ScalarNode的候选节点if candidate.Kind ! ScalarNode { return Context{}, fmt.Errorf(cannot convert node at path %v of tag %v to number, candidate.GetNicePath(), candidate.Tag) }2. 标量值无法解析为数字当标量值既不能解析为 int 也不能解析为 float 时典型如 null、布尔值、普通文本报错cannot convert node value [值] at path 路径 of tag tag to number算子文档给出了官方示例。执行yq --null-input .a.b | to_number输出Error: cannot convert node value [null] at path a.b of tag !!null to number这里--null-input即-n表示不读取输入文件、直接以 null 作为输入文档.a.b路径不存在因而值为 null最终触发!!null无法转换的错误。测试用例同样记录了这一错误信息operator_to_number_test.go保证该行为受回归测试约束。jq 兼容tonumber写法同样可用如果习惯 jq 的拼写yq 也支持把to_number写作tonumber不带下划线。词法规则里用正则to_?number同时匹配两种写法lexer_participle.go并在 operation.go 中统一注册为TO_NUMBER操作类型二者最终都进入同一个toNumberOperator处理器。测试场景中专门有一条skipDoc: true的用例验证了这一等价性operator_to_number_test.goyq .[] | tonumber sample.yml与to_number产生完全一致的结果。因此从 jq 迁移到 yq 时无需改写该算子。底层实现toNumberOperator的执行过程to_number的操作处理器是toNumberOperatoroperator_to_number.go整体是一个遍历-判定-重建的流程遍历匹配节点从上下文MatchingNodes链表逐个取出候选节点CandidateNode标量检查非标量节点立即返回错误数字透传节点 tag 已是!!int或!!float时直接把原节点压入结果链表不做任何转换转换重建否则调用tryConvertToNumber成功时通过candidate.CreateReplacement(ScalarNode, tag, candidate.Value)生成一个保留原值、但标签已更新为新数字类型的新节点失败报错转换失败则返回带路径与值的错误信息。值得注意的是第 4 步CreateReplacement保留了节点的原始字符串值仅替换 tag。换句话说to_number不做字符串 → Go 数值 → 字符串的重写而是直接改写类型标签让下游编码器按数字类型对原值进行格式化输出这也是它性能开销小、语义清晰的原因。真实场景中的组合用法to_number最常见的价值在于当 YAML/JSON 输入中的数字被写成字符串例如来自 CSV、环境变量注入或人工手写带引号的配置而下游的排序、比较、算术或条件判断又需要真正的数值类型时先用to_number完成归一化。例如将字符串数组按数值大小排序yq [.[] | to_number] | sort sample.yml或与select配合做数值范围过滤yq .[] | select(to_number 100) sample.yml由于to_number是纯标量转换算子它可以安全地出现在管道任意位置且对已是数字的节点零副作用因此也常用于对异构数据部分已数字化、部分仍为字符串的批量清洗。小结to_number是一个语义简单但边界行为明确的类型转换算子转换规则先按 int含下划线、十六进制、八进制等 YAML 写法解析失败再按 float含科学计数法解析幂等性已是!!int/!!float的节点原样透传失败场景复合节点直接报错标量值解析失败会给出包含节点路径、原始值与 tag 的详细错误信息jq 兼容tonumber与to_number等价实现要点底层通过改写节点 tag 而非重写字符串完成转换保留原值仅更新类型标签。相关参考文件算子文档、实现源码、测试用例、整数解析实现。【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进