Vim — инкрементная нумерация с помощью поиска и замены регулярных выражений

У меня есть этот код:

array ('id' => 1, 'name' => "Murka", 'date_of_birth' => "2014-10-31", "breed_id" => 1),
array ('id' => 1, 'name' => "Jurka", 'date_of_birth' => "2014-11-31", "breed_id" => 2),
array ('id' => 1, 'name' => "Nyash", 'date_of_birth' => "2014-12-31", "breed_id" => 3),
array ('id' => 1, 'name' => "Meowy", 'date_of_birth' => "2014-01-31", "breed_id" => 4),
array ('id' => 1, 'name' => "Yummi", 'date_of_birth' => "2014-10-31", "breed_id" => 2),
array ('id' => 1, 'name' => "Barss", 'date_of_birth' => "2014-05-31", "breed_id" => 2),
array ('id' => 1, 'name' => "Nonam", 'date_of_birth' => "2014-05-31", "breed_id" => null

Я хочу изменить все 'id' => 1 (кроме 1-го), чтобы число увеличилось на 1. Этого легко добиться с помощью Emacs:

M-x replace-regexp
\(1,\)
\,(1+ \#),

Как описано здесь. После некоторых исследований максимум, которого я смог достичь с Vim, это (вдохновленный здесь):

:let i=1 | g/1,/ s//\=i/ | let i+=1

Но это удаляет все следующие запятые:

array ('id' => 1 'name' => "Murka", 'date_of_birth' => "2014-10-31", "breed_id" => 1),
array ('id' => 2 'name' => "Jurka", 'date_of_birth' => "2014-11-31", "breed_id" => 2),
array ('id' => 3 'name' => "Nyash", 'date_of_birth' => "2014-12-31", "breed_id" => 3),
array ('id' => 4 'name' => "Meowy", 'date_of_birth' => "2014-01-31", "breed_id" => 4),
array ('id' => 5 'name' => "Yummi", 'date_of_birth' => "2014-10-31", "breed_id" => 2),
array ('id' => 6 'name' => "Barss", 'date_of_birth' => "2014-05-31", "breed_id" => 2),
array ('id' => 7 'name' => "Nonam", 'date_of_birth' => "2014-05-31", "breed_id" => null),

Так что я должен исправить это (я знаю, что это легко).

Мне известно об этом и макросах, мне просто интересно знать, есть ли какие- командное решение строки в Vim.

Более общий вопрос: возможно ли в Vim внедрить некоторую логику, например условные операторы, манипулируя обратными ссылками регулярных выражений? Примером этого в Emacs будет:

C-M-% \(^.*\)\(linear-gradient(\)\(to right\|to bottom\)\(.*$\) <RET>
\& C-q C-j
\1-prefix-\2\,(if (equal "to right" \3) "left" "top")\4

Это помогло мне год с лишним назад рефакторить какой-то огромный страшный HTML-код, в котором было много встроенного CSS.


person a1111exe    schedule 31.10.2014    source источник


Ответы (3)


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

:let i=1 | g/1(\,\)\@=/ s//\=i/ | let i+=1

Теперь он заменит только 1.

person Jeff    schedule 31.10.2014
comment
Большое спасибо, это работает! Добавлю в избранное :) - person a1111exe; 31.10.2014
comment
Вы можете упростить регулярное выражение, используя \ze вместо положительного прогноза. например :let i=1 | g/1\ze,/ s//\=i/ | let i+=1 - person Peter Rincker; 01.11.2014
comment
:пусть я=1 | g/1\ze,/ s//\=i/ | пусть i+=1 действительно используется для меня полностью. Пожалуйста, дайте мне знать, можно ли выбрать диапазон строк. Значит мне нужно заменить только строки с 10 по 20 в файле. Как мы можем это указать: - person imbichie; 20.03.2015

Действительно простое решение:

:%norm f1s^R=line('.')^M

Получается так:

:%norm f1s<C-v><C-r>=line('.')<C-v><CR>

Если вам неудобно вводить полные макросы в командной строке, вы можете добиться того же результата, записав:

qq
f1s<C-r>=line('.')<CR>
q
[range]@q
person romainl    schedule 31.10.2014
comment
Этот способ для меня немного эзотеричен, но он работает, и я обязательно попробую. Большое спасибо! - person a1111exe; 01.11.2014

Другой подход. перейдите на вторую строку, поместите курсор над первой 1, теперь начните визуальный выбор блока Ctrl-v, нажимайте j до строки, которую вы хотите увеличить, и нажмите g < kbd>Ctrl-a

person SergioAraujo    schedule 20.11.2020