PAYATHON 2026

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 为字符串的对象。

备注:内容仅供参考。