Jq — использовать регулярное выражение в json в тестовой функции

У меня есть json, содержащий регулярное выражение

[
  {
     "name": "For teachers",
     "regex": "^Apple "
  },
  {
     "name": "Long and yellow",
     "regex": "banana$"
  },
  {
     "name": "Cantaloupe",
     "regex": ".*/melon/.*"
  }
]

Я хотел использовать значение .regex в тестовой функции, например.

>>> jq '. | select( "path/to/melon/data" | test( .regex ) )' test.json
jq: error (at test.json:14): Cannot index string with string "regex"

Я пытаюсь проверить, соответствует ли переданная строка какому-либо из .regex в json и возвращает ли она соответствующий .name.

В приведенном выше test.json передача строки => вывод:

  • запуск "Яблоки" => "Для учителей"
  • окончание "банан" => "длинный и желтый"
  • содержащий текст "/melons/" => "Canteloupe"

Если совпадений несколько, верните все значения .name, где .regex соответствует переданной строке. Итак, из комментариев: "Яблоко или это /дыня/банан" => [ "Для учителей", "Длинный и желтый", "Дыня" ]


Я подумывал попробовать что-то вроде создания команды sed, но я не зашел так далеко, и я думаю, что добавление того, что у меня было, вызывало путаницу, а не разъяснение. Оставлю это здесь, чтобы комментарии имели смысл.

>>> echo "path/to/melon/data" | sed -E -e 's#^Apple #For teachers #g' -e 's#banana$#long and yellow#g' -e 's#.*/melon/.*#Cantaloupe#g'
Cantaloupe
>>> echo "Is this banana" | sed -E -e 's#^Apple #For teachers#g' -e 's#banana$#long and yellow#g' -e 's#.*/melon/.*#Cantaloupe#g'
Is this long and yellow

Я хочу, чтобы поведение было похоже на этот sed, но без необходимости создавать множество -e вариантов из jq print.

Я уверен, что смогу заставить что-то подобное работать, поэтому каждый раз, когда эхо-строка соответствует .regex, она возвращает соответствующий .name, но это такой хак ... даже для меня! (Примечание: этот sed не делает то, что я хочу, за исключением случая с дыней, потому что он заменяет совпадающий текст, а не отвечает текстом)

Пожалуйста, следуйте рекомендациям по минимальному воспроизводимому примеру. Содержит ли «test.json» показанный образец JSON? Команды sed выполняют преобразования, которых test явно не делает, поэтому уточните требования.

peak 21.11.2022 19:00
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
1
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать параметр --raw-input (или -R) для чтения в строке и параметр --argfile для чтения в файле регулярного выражения JSON:

echo "path/to/melon/data" |
jq -Rr --argfile rs regex.json '
  $rs[] as $r
  | if test($r.regex) then $r.name else empty end
'
Cantaloupe

Если строка содержится где-то во входном JSON, вам явно не нужна опция --raw-input (или -R):

jq -r --argfile rs regex.json '
  ...traverse to the string... | $rs[] as $r
  | if test($r.regex) then $r.name else empty end
' input.json

Это выведет «длинный и желтый» для ввода «Этот банан», но он должен вывести «Это длинный и желтый» (насколько я понимаю).

knittl 21.11.2022 20:24

@knittl Не совсем понятно, что и как OP хочет обработать в случае совпадения, поэтому я остался с их подходом test, который можно легко изменить, например, на gsub.

pmf 21.11.2022 20:28

Пример sed ("чтобы он имел поведение, подобное этому sed") выполняет подстановку.

knittl 21.11.2022 20:30

@knittl Если не указано иное, я стараюсь делать как можно меньше предположений. Конечно, ОП всегда может уточнить свои требования, поэтому я могу соответствующим образом адаптировать свой ответ.

pmf 21.11.2022 20:31

Это выглядит хорошо, попробую завтра и вернусь

Martin 21.11.2022 21:53

Похоже, вы хотите применить свой массив регулярных выражений по очереди к своей входной строке. Другими словами: сокращение ваших входных данных путем агрегирования результатов операции подстановки.

reduce $regex[0][] as $re (.; gsub($re.regex; $re.name))

Предоставьте $regex через --slurpfile и обязательно прочитайте исходный ввод (-R) и запишите необработанный вывод (-r):

$ echo "Is this banana" | jq -Rr --slurpfile regex test.json 'reduce $regex[0][] as $re (.; gsub($re.regex; $re.name))'
Is this Long and yellow

Применяются все замены:

$ echo "Apple or Is this melon a banana" | jq -Rr --slurpfile regex test.json 'reduce $regex[0][] as $re (.; gsub($re.regex; $re.name))'
For teahcersor Is this melon a Long and yellow

И будет применяться к уже замененным строкам. Итак, если бы у вас были "^a"=>"x" и "x"=>"y", то ввод "abc" закончился бы как "ybc".

$ echo "Apple or Is this /melon/ a banana" | jq -Rr --slurpfile regex test.json 'reduce $regex[0][] as $re (.; gsub($re.regex; $re.name))'
Cantaloupe

И если вы хотите напечатать только первую возможную замену, может сработать следующее (хотя я уверен, что есть более умный способ, это выглядит запутанным):

$ echo "Apple or Is this /melon/ a banana" | jq -Rr --slurpfile regex test.json '
. as $in 
| $regex[0] 
| map(
  . as $re
  | $in
  | select(test($re.regex))
  | gsub($re.regex; $re.name)
) 
| first
'
For teahcersor Is this /melon/ a banana

После обновлений вопроса вот ответ на последнюю версию:

$ echo "Apple or Is this /melon/ a banana" | jq -Rr --slurpfile regex test.json '
. as $in 
| $regex[0] 
| map(
  select(. as $re | $in | test($re.regex))
  | .name
)
'
[
  "For teahcers",
  "Long and yellow",
  "Cantaloupe"
]

Спасибо, я тоже рассмотрю сокращение и выберу свой любимый. Я обновил свой вопрос, чтобы уточнить ожидаемый результат. Было поздно, и я поторопился, извините.

Martin 21.11.2022 21:59

Другие вопросы по теме