Удалите большие куски из json, используя vim

У меня огромный файл (1/2 миллиона строк) json.

Мне нужно удалить набор записей, содержащих определенную строку.

{ "bla1": { "Part1": "Plop1", "Part2": "Plop2", "Part3": "BadFling1<stuff>", "part4": "Plop4", }, "bla2": { "Part1": "Plop1", "Part2": "Plop2", "Part3": "<stuff>", "part4": "Plop4", }, // etc for many more entries } 

Все записи имеют «BadFling1» в качестве префикса для записи «Part3».

Мне было интересно, как лучший способ автоматизировать удаление всех записей, которые включают «BadFling1». Так, например, результат удаления плохой записи сверху:

 { "bla2": { "Part1": "Plop1", "Part2": "Plop2", "Part3": "<stuff>", "part4": "Plop4", }, // etc for many more entries } 

Моя первая попытка работала, но не достаточно быстро (поскольку она была немного ручной).

 /BadFling1 qan3k5ddq :map zn@a 

Теперь удерживайте клавишу «z».

Мой vim foo недостаточно силен, поэтому я не уверен, как автоматизировать процессы лучше в vim. Любая помощь оценивается.

Альтернативные подходы в bash (или другие инструменты командной строки также приветствуются).

4 Solutions collect form web for “Удалите большие куски из json, используя vim”

Попробуйте это в vim :

 :g/BadFling/normal [{V]}d 

:global команда выполняет команду на всех строках, соответствующих шаблону (я использовал BadFling в качестве примера – при необходимости отрегулируйте). В этом случае выполняется команда :normal , которая запускает команды нормального режима. Цель этого – использовать силу команд [{ и ]} движения vim которые перемещаются между парами скобок. Компонент Vd используется для удаления linuxise. Это не так надежно, как парсер JSON, но работает, полагая, что каждая часть "blah1" содержится в пределах собственного набора строк, и поэтому удаление строки не случайно удалит все, что принадлежит другому блоку. Например, метод удаления linewise не будет работать, если у вас есть что-то вроде

  ... end of block you want to keep }, "blah1" : { block you want removed }, "blah2" : { start of block you want to keep ... } 

Кроме того, [{ использует только непосредственный родительский блок, поэтому, если у вас есть дополнительные уровни вложенности, он также не будет работать.

Вы можете сделать это с помощью grep и diff , если ваша версия diff достаточно современна:

 ire@localhost$ grep -B 3 -A 2 BadFling1 huge.json | diff --changed-group-format="%>" --unchanged-group-format="" - huge.json { "bla2": { "Part1": "Plop1", "Part2": "Plop2", "Part3": "<stuff>", "part4": "Plop4", }, // etc for many more entries } 

grep вытащил плохие записи, извлекая линии, окружающие ваш матч. diff удаляет их из оригинала. Как указано в комментариях, это решение требует, чтобы размеры блоков были согласованными, а соответствующая строка была в одном месте внутри каждого блока (как в вашем примере).

Если бы это было не так (изменение размера записи или ненадежное позиционирование элементов записи), я бы воспринял это как подсказку для написания сценария быстрого разбора. Вы можете легко и безопасно удалить эти записи только с несколькими строками Python, который имеет встроенный парсер JSON.

Вот решение в awk:

 awk '/".*":\ {/ { open=line; skip_block=0 } /"Part3":\ "BadFling1/ { skip_block=1 } /},/ { if (skip_block) { line=open; next } } { lines[line++]=$0 } END { for (i=0;i<=line;i++) { print lines[i] } }' yourfile > clean 

Это не очень хорошо проверено, но вам нужно начать. Он будет работать, даже если блоки имеют переменную длину и не заботятся о том, где в блоке расположена линия дисквалификации.

Объяснение:

строка 1: если строка соответствует началу блока, обратите внимание на позицию в массиве, отметьте блок как можно дольше

строка 2: если строка совпадает с линией дисквалификации и отметьте блок

строка 3: совпадение с концом блока. если блок отмечен, сбросьте позицию в массиве до того места, где был запущен блок, и перейдите к следующей строке

строка 4: добавьте текущую строку в массив и счетчик счетчиков нарастания

строка 5: когда закончите чтение файла, напечатайте массив, содержащий только «хорошие» блоки

Вы можете реализовать одно и то же в bash, но awk будет намного быстрее, и, на мой взгляд, это то, для чего строится awk, без необходимости вытаскивать «более тяжелый» язык.

используя vim:

 :%s/BadFling1//g 

будет искать все вхождения «BadFling1» и заменить его на «».

  • Пунктуация заклинания Vim для ⸮
  • Связывание ключа Vim для циклического перехода через окна
  • Можем ли мы исправить уже исправленный шрифт?
  • Vim - Cursorline включается после сохранения удаленного файла
  • Тип файла не обнаружен
  • Отключить или удалить по умолчанию vim keybinding
  • Горячие клавиши vim с переменными
  • Поиск и замена двух слов командой ex
  • Vim потеряет способность копировать клиенту клип через SSH
  • Как установить bash-псевдонимы и переменные из vim?
  • vim / emacs для просмотра рекурсивных результатов поиска grep?
  • Linux и Unix - лучшая ОС в мире.