jq 如何筛选不包含任一指定子串的对象?
数据阿明
结论
先将当前对象的 fruits 字符串保存到变量,再逐一检查黑名单中的子串。原表达式里的 contains(.) 会让当前黑名单项既作为被检查的字符串,也作为查找内容,因此判断结果不符合预期。
jq --argjson exl '["apple","nana"]' '
.list[]
| select((.fruits | type) == "string")
| select(
.fruits as $fruit
| [$exl[] as $needle | ($fruit | contains($needle))]
| any
| not
)
' input.json
对题目给出的数据,这段命令会输出 fruits 为 peach 的对象。
原表达式的问题
原过滤器是:
select(.fruits | any($exl[]; contains(.)) | not)
any(generator; condition) 会对生成器产生的每个值执行 condition。这里 $exl[] 依次产生 "apple" 和 "nana"。执行 contains(.) 时,. 指向当前黑名单项,所以实际效果是检查该项是否包含自身。要按预期过滤,需要先保存对象的 fruits 值,再把黑名单项传给 contains。
过滤器如何工作
.fruits as $fruit将当前对象的字符串保存到$fruit。$exl[] as $needle依次取出每个黑名单子串。$fruit | contains($needle)检查fruits是否包含当前子串。any检查是否至少有一个子串匹配;末尾的not则保留没有匹配任何子串的对象。
前面的类型检查会排除缺少 fruits 属性或其值不是字符串的对象。如果能保证该属性始终是字符串,可以省略这层 select。黑名单为空时,any 对空数组返回 false;经过 not 后,会保留所有 fruits 为字符串的对象。
备注:内容仅供参考。
