0

I have this code:

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

I'll want to change all 'id' => 1 (except the 1st) so the number will increment by 1. It's simple to achieve with Emacs:

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

As described here. After some research the maximum that I've been able to achieve with Vim is (inspired from here):

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

But this removes all the following commas:

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),

So I have to fix it (I know it's easy).

I am aware of this and macros, I'm just interested to know if there any one-line command solution in Vim.

More general question: is it possible in Vim to inject some logic like conditional statements, manipulating on regex back references? The example for this in Emacs would be:

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

This one helped me about a year+ ago to refactor some huge scary HTML code that had a much of inline CSS.

Community
  • 1
  • 1
a1111exe
  • 641
  • 4
  • 18

3 Answers3

4

I don't have an answer to your general question, but I do have one for your specific situation. You can make your command work by putting the comma into a positive look-ahead, like this:

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

Now it will only replace the 1.

Jeff
  • 1,787
  • 9
  • 14
  • Thanks a lot, it works! Adding this to my favorites :) – a1111exe Oct 31 '14 at 19:45
  • 1
    You can simplify your regex by using `\ze` instead of a positive lookahead. e.g. `:let i=1 | g/1\ze,/ s//\=i/ | let i+=1` – Peter Rincker Oct 31 '14 at 23:45
  • :let i=1 | g/1\ze,/ s//\=i/ | let i+=1 is really use full for me. Please let me know is it possible to select the range of lines. Means I need to replace only lines from 10 to 20 in the file. How we can specify that: – imbichie Mar 20 '15 at 08:04
3

A really easy solution:

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

Obtained like this:

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

If you are not comfortable with typing complete macros on the command-line you can achieve the same result via recording:

qq
f1s<C-r>=line('.')<CR>
q
[range]@q
romainl
  • 186,200
  • 21
  • 280
  • 313
  • This way is a bit esoteric for me, but it works, and I'll definitely give it a try. Thank you very much! – a1111exe Oct 31 '14 at 21:29
0

Another approach. go to the second line, put the cursor over the first 1, now start a visual block selection Ctrl-v, press j until the line you want increment and press g Ctrl-a

SergioAraujo
  • 11,069
  • 3
  • 50
  • 40