Заменить каждое совпадение увеличенным числом - PullRequest
0 голосов
/ 09 октября 2018

Мне нужно добавить свойство ID в список объектов в файле JSON.Я нашел этот полезный встроенный Perl-скрипт, который заменяет каждое совпадение случайным intкак это

{
    "id" : XYZ
},
{
    "id" : XYZ
},
{ ... }

с этим:

{
    "id" : 1
},
{
    "id" : 2
},
{ ... }

Я пробовал это:

:%! perl -pne 's/XYZ/(0..100)/ge'

, но это предполагает, что я знаю длину списка заранееа также не работает, как ожидалось.Я знаю, что могу получить несколько совпадений, используя что-то вроде этого:

:%s/"id" : XYZ//gn

Ответы [ 4 ]

0 голосов
/ 10 октября 2018

Для тех, кто ищет чистое решение Vim, вот более каноническое и общее решение, чем в ответе @ sidyll, которое не требует :perldo или :global, а также будет работать с несколькими совпадениями в строке (добавляяg флаг :substitute):

со встроенной заменой

В Vim вы можете использовать :help sub-replace-expression для замены текста произвольными выражениями.К сожалению, приращение переменной - это оператор в Vim, а не выражение.Либо приходится прибегать к уловкам, таким как использование длины List в качестве счетчика (add() можно использовать в выражении):

:let c = [] | %substitute/XYZ/\=len(add(c, 0))/

Или вам нужно определить отдельную функцию (один раз):

function! Increment()
    let g:i += 1
    return g:i
endfunction
let g:i = 0 | %substitute/XYZ/\=Increment()/

С плагином

Синтаксис выражения немного странный (но если вы в Perl, вы привыкли к гораздо худшему :-).Кроме того, явная отдельная инициализация счетчика (и функции) является громоздкой.Мой плагин PatternsOnText улучшает встроенную команду :substitute в нескольких вариантах.Среди них :SubstituteExecute, который извлекает выгоду из предопределенного объекта контекста:

:%SubstituteExecute /XYZ/ let v:val.n += 1 | return v:val.n

Перенумерация является настолько частой задачей, что плагин даже имеет специальную команду для нее:

:Renumber /XYZ/

Предостережения

  • Структурированный, но гибкий синтаксис, такой как HTML или JSON, плохо подходит для анализа регулярных выражений, если только вы не уверены, что используемое подмножество разрешенного синтаксиса является очень регулярным (например, потому что вы знаете источник вводаи / или прошли ввод через симпатичный принтер).Предпочитайте специализированные инструменты обычным (т. Е. Используйте xmlstarlet для XML и jq для JSON вместо grep и sed).
0 голосов
/ 09 октября 2018

Используя Perl , встроенный в JSON-парсер (в 5.14+), вам не нужно иметь дело со строками, которые могут появляться в других местах, должны ли строки и числа быть заключены в кавычки или нет, или другими сложностями, выможно просто изменить JSON как структуру данных (возможно, потребуется изменить код, чтобы изменить правильную часть вашей полной структуры JSON):

perl -0777 -MJSON::PP -E'my $data = decode_json readline; $_->{id} = ++$i foreach @$data; print encode_json $data'

Еще лучше было бы использовать JSON ::Возможно, XX по умолчанию будет устанавливать и использовать намного более быстрый синтаксический анализатор.

Переключатель -0777 - это соглашение для однострочников, вызывающих readline или оператор <>(также используется ключом -p) для одновременного возврата всего ввода.

0 голосов
/ 09 октября 2018

Если вы делаете это в Vim и у вас есть функция +perl, то:

:%perldo s/XYZ/++$i/e

Если вы хотите сделать это с помощью простых команд Vim, вы можете следовать той же логике и использовать переменную,Однако его необходимо создавать заранее и увеличивать после каждой замены.Таким образом, вам может потребоваться помощь от :g для выполнения двух команд:

:let i=0
:g/XYZ/let i+=1|s//\=i

Пустой s// повторно использует шаблон из :g.

В качестве альтернативы, просто отфильтруйте его через Perlкак вы делали изначально:

:%!perl -pe 's/XYZ/++$i/e'
0 голосов
/ 09 октября 2018

-p уже обрабатывает входные данные построчно, поэтому -n является избыточным.

perl -pe 's/XYZ/$i++/ge'

$i++ возвращает значение $i в числовом контексте и добавляет к нему 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...