十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

yq 相等与不相等运算符(== / !=)完全指南:从基础匹配到 glob 通配与空值语义

yq 相等与不相等运算符(== / !=)完全指南:从基础匹配到 glob 通配与空值语义 yq 相等与不相等运算符 / !完全指南从基础匹配到 glob 通配与空值语义【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yqyqGitHub_Trending/yq/yq是一个可移植的命令行 YAML、JSON、XML、CSV、TOML、HCL 与 properties 处理器等于与!不等于是其表达式语言中最基础、最高频的布尔运算符。本文以官方运算符文档 equals.md 为主体结合 operator_equals.go 源码与 operator_equals_test.go 测试用例系统讲解这两个运算符的语法、匹配规则、与select的组合实战以及空值、不存在键、字符串通配等边界语义读完即可在 yq 表达式中熟练完成各类相等性判断与过滤任务。一、运算符基础语法与返回类型与!都是二元布尔运算符当左侧操作数LHS与右侧操作数RHS相等时返回true否则返回false!的语义正好相反当 LHS 与 RHS 相等时返回false不相等时返回true。最基本的用法.a .b它的执行结果为布尔值true/false输出时会被格式化为 YAML 布尔节点。从源码角度看yq 在 operation.go 中注册了两个操作类型equalsOpTypeType: EQUALSNumArgs: 2Precedence: 40处理器为equalsOperatornotEqualsOpTypeType: NOT_EQUALSNumArgs: 2Precedence: 40处理器为notEqualsOperator。两者优先级均为 40与比较运算符、等同级它们都会被词法分析器 lexer_participle.go 中的Equals\s*\s*与NotEquals\s*!\s*规则识别为独立 token。表达式会先经过分词、转后缀expression_parser.go再构建表达式树执行与!两侧可以分别是路径、字面量或任意子表达式。二、与 select 组合最常见的实战形态原文档明确指出/!最常与select运算符配合用于从集合中筛选出满足条件的节点select(.a .b)select是一个过滤型运算符实现见 operator_select.go它接收一个布尔表达式仅保留结果为true的节点。因此select(.a .b)的含义是只保留那些.a与.b相等的节点select(.a ! .b)则相反。由于/!直接产出布尔候选节点由 operators.go 中的createBooleanCandidate构造它们天然适合作为select、and/or等布尔上下文boolean-operators.md的输入。相关运算符的完整关系可参考官方文档比较运算符compare.md、布尔运算符boolean-operators.md、select 运算符select.md。三、字符串匹配支持 glob 通配符yq 的/!对字符串比较并不是简单的逐字符相等判断而是支持*匹配零或多个字符与?匹配单个字符两种通配符。给定sample.yml- cat - goat - dog执行yq .[] | (. *at) sample.yml输出true true falsecat与goat都以at结尾匹配*atdog不匹配。.[]展开数组元素后逐个与模式比较这正是 operator_equals_test.go 中 Match string 场景所验证的行为。对应的不相等版本yq .[] | (. ! *at) sample.yml输出false false true模式匹配的具体实现在 matchKeyString.go 的matchKey函数中当 pattern 为空字符串时退化为精确比较当 pattern 为*时直接命中任意字符串其余情况调用deepMatch——一个参考 https://research.swtch.com/glob 实现、线性时间的经典 glob 匹配算法matchKeyString.go支持*与?通配。这意味着你可以在过滤表达式中写出select(.name prod-*)之类的模式筛选无需先切割字符串。四、数字匹配精确值比较对数字进行相等性判断时按数值本身精确比较。给定sample.yml- 3 - 4 - 5执行yq .[] | (. 4) sample.yml输出false true false不相等版本yq .[] | (. ! 4) sample.yml输出true false true从实现看当左右两侧都是标量节点lhs.Kind ScalarNode rhs.Kind ScalarNode时isEquals会对节点的字符串化值调用matchKeyoperator_equals.go因此数字、布尔等标量都走同一套比较逻辑上述场景在测试 operator_equals_test.go 中均有对应用例。数字也可以与表达式结果比较例如(.k | length) 0这种字段为空的判断见 operator_equals_test.go。五、空值与 null 语义/!对null有一套专门的处理逻辑。使用--null-input从零构造输入可以直接比较字面量null与波浪号~~在 yq 中同样表示 nullyq --null-input null ~输出true源码 operator_equals.go 中对应分支是只要左侧节点的 tag 是!!null就判定两侧相等当且仅当右侧 tag 也是!!null。更完整的空值比较矩阵如下null null→true测试用例见 operator_equals_test.goselect(.c ! null)在{a: {b: 10}}上不产生输出因为.c不存在即视为 null与 null 相等!为假见 operator_equals_test.goselect(null .c)在{a: {b: 10}}上保留整个文档见 operator_equals_test.go。六、不存在的键一个关键语义这是/!最容易踩坑、也最有价值的行为不存在的键被当作 null 参与比较。不存在的键不等于某个值给定sample.ymla: frog执行yq select(.b ! thing) sample.yml输出a: frog.b不存在被视为 nullnull 不等于字符串thing所以!为trueselect保留了整个文档。两个不存在的键彼此相等yq select(.b .c) sample.yml输出a: frog.b与.c都不存在二者相等select同样保留文档。测试 operator_equals_test.go 将这两个行为固化为 Non existent key doesnt equal a value 与 Two non existent keys are equal 两个场景。从实现原理看当某侧节点不存在时crossFunction会把该侧候选节点置为nil见 operators.go 与resultsForRHS中对空 RHS 的处理 operators.go随后isEquals的分支逻辑如下operator_equals.go两侧都为nil→ 判定相等返回true翻转后为false仅 LHS 为nil→ 相等当且仅当 RHS 的 tag 为!!null仅 RHS 为nil→ 相等当且仅当 LHS 的 tag 为!!null。所以键不存在与显式 null在比较语义上是一致的这解释了为什么select(.c ! null)不会选中键不存在的文档。如果你的场景需要区分键不存在与值为 null应改用has运算符has.md先判断键是否存在。七、运算符底层原理跨函数求值与!的执行都走 yq 的跨函数cross function求值框架。入口处理器定义在 operator_equals.go 与 operator_equals.gofunc equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { return crossFunction(d, context, expressionNode, isEquals(false), true) } func notEqualsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { return crossFunction(d, context.ReadOnlyClone(), expressionNode, isEquals(true), true) }两者共享同一个核心比较函数isEquals(flip bool)传入flipfalse!传入fliptrue在最终结果上取反crossFunctionoperators.go首先计算 LHS 的所有匹配节点再对每个 LHS 节点计算 RHSresultsForRHS最后把布尔结果收集进输出上下文!使用context.ReadOnlyClone()保证不相等运算不会意外污染上下文不会触发写入语义。这也解释了的多对多语义当 LHS 或 RHS 匹配多个节点时运算会在它们之间做笛卡尔式的两两比较并分别产出结果。八、与其他运算符的关系/!在 yq 运算符体系中的定位与比较运算符、、等由 compare.md 讲解优先级同为 40operation.go但比较的是大小关系而非相等关系与布尔运算符and、or、any等boolean-operators.md可以把多个/!的结果组合成复合过滤条件例如select(.a x and .b ! y)与 select 运算符如上文所述/!是select最常用的谓词来源select.md。九、实战速查目标表达式字段与字面量相等select(.status active)字段不等于某值select(.status ! disabled)字符串后缀/前缀匹配select(.name *prod*)或select(.name prod-*)单字符通配select(.name a?c)按数量过滤空集合/空字段select((.items \| length) 0)筛选 null 值select(.value null)两个字段相等select(.a .b)键不存在也算 nullselect(.missing ! thing)会选中该文档使用要点总结字符串比较支持*/?通配matchKeyString.go精确匹配请确保模式中不含通配符不存在的键在比较中等价于 null两侧都缺失时为true与显式 null 比较也为true/!返回布尔节点可直接嵌套进select、and/or、if风格条件等布尔上下文输出格式默认 YAML如需 JSON 可加-ojson等格式参数参见 formatting-expressions.md。以上全部行为均有官方文档与测试双重佐证文档正文见 equals.md 与 equals.md 头部版测试用例见 operator_equals_test.go实现源码见 operator_equals.go、matchKeyString.go 与 operators.go。【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表