jq: select 当数组中有任何值时
jq: select when any value is in array
给定输入 json
[
{"title": "first line"},
{"title": "second line"},
{"title": "third line"}
]
我们如何才能仅提取包含第二个 "filter" 数组中列出的关键字的标题。例如在此处使用 shell 变量:
filter='["second", "third"]'
这种情况下的输出是
[
{"title": "second line"},
{"title": "third line"}
]
另外,如何使用数组过滤器取反。
例如:return 仅上一个示例中的 "first line" 条目。
有一个但是使用的是旧版本的jq。
我希望当前版本的 jq 有更多 intuitive/readable 方法可以做到这一点。
您可以结合使用 jq
和 shell 技巧,使用数组来生成过滤器。首先要生成 shell 数组,请使用 shell 中的数组符号,如下所示。请注意,以下 bash
数组的符号将 而不是 在其定义中将 ,
作为分隔符。现在我们需要生成一个正则表达式过滤器来匹配字符串,所以我们生成一个交替运算符
filter=("first" "second")
echo "$(IFS="|"; echo "${filter[*]}"
first|second
您没有提到字符串是否仅在第一个或最后一个匹配,或者可能在 .title
部分的任何位置。下面的正则表达式匹配字符串中任意位置的字符串。
现在我们要在 jq
中使用此过滤器来匹配 .title
字符串,如下所示。注意使用 not
来否定结果。要提供实际匹配,请删除 |not
.
部分
jq --arg re "$(IFS="|"; echo "${filter[*]}")" '[.[] | select(.title|test($re)|not)]' < json
解决涉及单词 "any" 的问题的一种方法通常是使用 jq 的 any
,例如使用您的 shell 变量:
jq --argjson filter "$filter" '
map((.title | split(" ")) as $title
| select(any( $title[] as $t
| $filter[] as $kw
| $kw == $t )))' input.json
否定
与形式逻辑一样,您可以使用all
或any
(结合否定)来解决否定问题。但是不要忘记,如果你使用 not
,
jq 的 not
是一个零元数过滤器。
jq --argjson filter "$filter" '
map((.title | split(" ")) as $title
| select(all( $title[] as $t
| $filter[] as $kw
| $kw != $t )))' input.json
其他方法
上面使用 "keyword matching" 因为那是问题指定的内容,但是当然可以很容易地修改上面的 jq 表达式以使用正则表达式或其他一些类型的匹配。
如果关键字列表很长,那么无疑需要更好的数组交集算法。
给定输入 json
[
{"title": "first line"},
{"title": "second line"},
{"title": "third line"}
]
我们如何才能仅提取包含第二个 "filter" 数组中列出的关键字的标题。例如在此处使用 shell 变量:
filter='["second", "third"]'
这种情况下的输出是
[
{"title": "second line"},
{"title": "third line"}
]
另外,如何使用数组过滤器取反。 例如:return 仅上一个示例中的 "first line" 条目。
有一个
您可以结合使用 jq
和 shell 技巧,使用数组来生成过滤器。首先要生成 shell 数组,请使用 shell 中的数组符号,如下所示。请注意,以下 bash
数组的符号将 而不是 在其定义中将 ,
作为分隔符。现在我们需要生成一个正则表达式过滤器来匹配字符串,所以我们生成一个交替运算符
filter=("first" "second")
echo "$(IFS="|"; echo "${filter[*]}"
first|second
您没有提到字符串是否仅在第一个或最后一个匹配,或者可能在 .title
部分的任何位置。下面的正则表达式匹配字符串中任意位置的字符串。
现在我们要在 jq
中使用此过滤器来匹配 .title
字符串,如下所示。注意使用 not
来否定结果。要提供实际匹配,请删除 |not
.
jq --arg re "$(IFS="|"; echo "${filter[*]}")" '[.[] | select(.title|test($re)|not)]' < json
解决涉及单词 "any" 的问题的一种方法通常是使用 jq 的 any
,例如使用您的 shell 变量:
jq --argjson filter "$filter" '
map((.title | split(" ")) as $title
| select(any( $title[] as $t
| $filter[] as $kw
| $kw == $t )))' input.json
否定
与形式逻辑一样,您可以使用all
或any
(结合否定)来解决否定问题。但是不要忘记,如果你使用 not
,
jq 的 not
是一个零元数过滤器。
jq --argjson filter "$filter" '
map((.title | split(" ")) as $title
| select(all( $title[] as $t
| $filter[] as $kw
| $kw != $t )))' input.json
其他方法
上面使用 "keyword matching" 因为那是问题指定的内容,但是当然可以很容易地修改上面的 jq 表达式以使用正则表达式或其他一些类型的匹配。
如果关键字列表很长,那么无疑需要更好的数组交集算法。