Vim Tips Wiki
Register
Advertisement
Tip 918 Printable Monobook Previous Next

created 2005 · complexity basic · version 6.0


This tip presents different methods showing how to insert a list of increasing numbers.

Making a list[]

It is easy to insert a list of ascending numbers, for example, this command inserts five lines after the current line:

:put =range(11,15)

The five lines are:

11
12
13
14
15

If wanted, the lines can be inserted after a particular line number, for example :123put =range(11,15) inserts them after line number 123, while :0put =range(11,15) inserts the lines at the start of the buffer, and :$put =range(11,15) inserts them after the last line.

An equivalent command is :call append(123,range(11,15))) to insert the five lines after line number 123, for example.

The list of numbers can be formatted. For example, the following inserts 150 lines, where each line contains a number displayed in four columns with leading zeros.

:put =map(range(1,150), 'printf(''%04d'', v:val)')

The results range from 0001 to 0150. The map() function replaces each value with the result of the expression, which must be given as a string (the double '' presents a single apostrophe when inside an apostrophe-quoted string). In the expression, v:val represents each value from the list in the first argument.

Here is another example, using a loop rather than map():

:for i in range(1,10) | put ='192.168.0.'.i | endfor

Executing this command inserts the following after the current line:

192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10

Substitute with ascending numbers[]

Suppose you want to replace each occurrence of "abc" with "xyz_N" where N is an ascending number (xyz_1, xyz_2, xyz_3, and so on).

One approach uses the following command:

:let i=1 | g/abc/s//\='xyz_'.i/ | let i=i+1

However, this only changes the first abc on each line. Adding the g flag for a global substitute does not help as i is only incremented once per matching line.

The following trick uses the a register which can be changed with the setreg() function:

:let @a=1 | %s/abc/\='xyz_'.(@a+setreg('a',@a+1))/g

As setreg returns 0 rather than a useful value, the replacement expression (\=) calls setreg by adding it to register a.

Using a function[]

Put the following script in your vimrc or in a file in your plugin directory.

" Add argument (can be negative, default 1) to global variable i.
" Return value of i before the change.
function Inc(...)
  let result = g:i
  let g:i += a:0 > 0 ? a:1 : 1
  return result
endfunction

Suppose you want to replace each occurrence of "abc" with "xyz_N" where N is an ascending number (xyz_1, xyz_2, xyz_3, and so on). To do this, enter the command:

:let i = 1 | %s/abc/\='xyz_' . Inc()/g

For another example, the following command replaces each occurrence of "abc" with a number that increases by 5, starting at 100 (the numbers will be 100, 105, 110, and so on):

:let i=100 | :%s/abc/\=Inc(5)/g

Incrementing selected numbers[]

In Vim 8, the first number in a selection can be incremented by pressing Ctrl-A. If the selection covers several lines, the first number in the selection on each line is incremented. Alternatively, numbers in a selection covering several lines can be converted to a sequence by typing g Ctrl-A. For example, start with the following line:

my_array[0] = 0;

Then copy it using Y6p (copy the line and paste it six times). The result is:

my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;

With the cursor on the first 0 in the first line, start a blockwise select by pressing Ctrl-V (or Ctrl-Q if you use Ctrl-V for pasting). Move the cursor down to select the first column of zeros, then press g Ctrl-A. Using Vim 8, that will give:

my_array[1] = 0;
my_array[2] = 0;
my_array[3] = 0;
my_array[4] = 0;
my_array[5] = 0;
my_array[6] = 0;
my_array[7] = 0;

Vim 7 and earlier need a script or a macro to create a sequence.

See also[]

Comments[]

An alternative is to make use of external seq command to generate the sequence and copy paste using visual block mode. E.g, see the below sample ex mode commands (you can copy paste these):

  • :new
    • This creates a new scratch window
  • :.!seq 1 15
    • This generate a sequence from 1 to 15,
    • Use seq -f \%2g 1 15 for right justification
  • :exe "normal! \<C-V>0G"
    • This selects the sequence in visual block mode and copies it
    • This is same as typing the sequence <CTRL-V>0Gy in normal mode
  • :bw!
    • This nukes the new scratch window
  • :normal! p
    • Paste the copied sequence in the original buffer.
    • This is same as typing p in normal mode
    • Make sure you are back in the original window and also the right location before pasting.
Advertisement