JQ: выберите, когда любое значение находится в массиве - PullRequest
0 голосов
/ 11 февраля 2019

С учетом ввода json

[
  {"title": "first line"},
  {"title": "second line"},
  {"title": "third line"}
]

Как можно извлечь только заголовки, которые содержат ключевые слова, которые перечислены во втором массиве «фильтр».Используя здесь переменную оболочки, например:

filter='["second", "third"]'

Выходные данные в этом случае будут

[
  {"title": "second line"},
  {"title": "third line"}
]

Кроме того, как использовать фильтр массива вместо отрицания.Например: вернуть только запись «первой строки» в предыдущем примере.

Существует аналогичный ответ , но с использованием старой версии jq.Я надеюсь, что есть более интуитивный / читабельный способ сделать это с текущей версией jq.

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Одним из способов решения проблемы, которая включает в себя слово «any», часто является использование jq's any, например, с использованием переменной оболочки:

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's not является фильтром нулевой арности.

jq --argjson filter "$filter" '
  map((.title | split(" ")) as $title
      | select(all( $title[] as $t
                    | $filter[] as $kw
                    | $kw != $t )))' input.json

Другие подходы

Вышеприведенное использование "соответствия ключевых слов" какэто то, что задает вопрос, но, конечно, вышеприведенные выражения jq можно легко изменить, используя регулярные выражения или какой-либо другой тип сопоставления.

Если список ключевых слов очень длинный, то лучший алгоритм пересечения массивов, несомненно, был бы желателен.

0 голосов
/ 11 февраля 2019

Вы можете использовать комбинацию jq и трюки с оболочкой, используя массивы для создания фильтра.Во-первых, чтобы создать массив оболочки, используйте обозначение массива из оболочки, как показано ниже.Обратите внимание, что приведенная ниже запись 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
...