How to generate a number sequence in file using vi or Vim?

Is there a way to generate a number sequence in vi or Vim?

For example, for an arbitrary range of lines i  through j (where i < j) in a file opened in Vim, is there a way to generate a number sequence from number 1 on line i all the way through number (j − i + 1) on line j?

Say, I have the following lines in a file:

this is line #1
this is line #2
this is line #3
this is line #4
this is line #5
this is line #6
this is line #7
this is line #8
this is line #9
this is line #10

I want to prefix the number sequence from line 4 to line 8 with numbers 1 through 5. After the operation, the resulting file should be as follows:

this is line #1
this is line #2
this is line #3
1 this is line #4
2 this is line #5
3 this is line #6
4 this is line #7
5 this is line #8
this is line #9
this is line #10

If this is possible, is there a way to use different step sizes for the generated sequence? For example, can 2 be used for the step size instead, so that the resulting sequence is 2, 4, 6, 8, etc.?

Note: The question “How to add line numbers to range of lines in Vim?” brings up a similar problem, but it is not the same.

42145 次浏览

Select the target lines in Visual mode, then run the Ex command

:'<,'>s/^/\=(line('.')-line("'<")+1).' '

Select several lines with V(Shift-v), then type command bellow:

:let i=1 | '<,'>g/^/ s//\=i . " "/ | let i+=2

Type :help sub-replace-expression to read more.

Here's a dirty trick but then life is composed of these. :)

ESC :r! for i in $(seq 1 10); do echo "This is line \#${i}"; done

Not cross platform.

Instead of a complicated construct you could simply use a macro with the CTRL-a function to increment a leading number. Example data:

aaa
bbb
ccc

first insert a start number and a space:

1 aaa
bbb
ccc

then record this macro on line 1 (<C-a> means press CTRL-a):

qq0yf 0j0P0<C-a>q

Explanation:

  1. qq: record macro into register q
  2. 0: go to first column.
  3. yf: yank all until and including the first space (remember your first line has 1 and a space).
  4. 0jP: go down and paste the pattern at the start of the line.
  5. 0<C-a>: go to first column and increment number by one.
  6. q: end macro recording.

this gives:

1 aaa
2 bbb
ccc

now you can apply this macro using @q as long as you want. If you need an increase of two just use CTRL-aCTRL-a instead of just once. Now you could apply this macro to consecutive lines, for example:

:.,$norm @q

will add leading line numbers for the rest of your file.

:4,8s/^/\=line(".")-3." "

will do what you want

if you need count=2:

:4,8s/^/\=2*(line(".")-3)." "

this will give you 2,4,6,8,10

line numbers are hard coded in my example, you could use V to select those lines you want to change.

A less flexible, but an easy to remember method is to use a renumbering plugin like Renumber.vim http://www.vim.org/scripts/script.php?script_id=189

If there aren't any numbers yet, like in the OP, some number should be inserted in their place. Renumber can handle the actual ordering and it does it based on just the first number.

In this example I'm using <C-v> to insert the starting number on all the lines you want numbered.

4G<C-v>4jGI1 <Esc>gv:Renumber

To use steps of two

:Renumber s2

The Nexus plugin provides the Series type and an object, s1, of that type used like this:

:4,8s/^/\=s1.next().' '/

Nexus also comes with an s0 Series object that yields 0 as its first .next() result. Both s0 and s1 use a 1-step increment. All Series objects have a .reset() method which sets them back to their initiated value. New Series objects can be created like the following call:

let s2 = Series(0, 2)

which creates a 2-step object meeting your second request (yielding: 2, 4, 6, 8, etc.).

I think all the proposed solutions are too difficult to remember, you can use it once but then you need to go into all details every time you use it (if you use it less than once a day or so).

I found the visual incrementing script really easy to install and use. Once it is installed in vim, you just need to generate a column of 0's, select it with Ctrl-V and write the command :I. It will then automatically generate increasing numbers on each line. There are also other features:

  • start with a number different from 0
  • left or right pad numbers with 0's (like 001, ..., 015)
  • decreasing or increasing numbers
  • increase by more than 1
  • dates (but you need an additional plugin), letters of the alphabet, daynames

This solves a more general problem because it works also at a position different from column 0, the column has just to be selectable with Ctrl-V.

The vimball of the plugin is here or here.

(if your vim has Perl support -- default in many Linux Distributions): Select the lines in visual mode (V) and do

:perldo s/^/++$z . " "/e

or

:4,8 perldo s/^/++$z . " "/e

Vim 7.4.754开始,可以使用g Ctrl-a,参见:help v_g_CTRL-A

Go to line #4, use Ctrl-v to blockwise select the first character, go down 4 lines, press Shift i, enter 0 (this is 0, followed by Space) and Esc to exit insert mode.

Now use gv to re-select the previously selected area. Press g Ctrl-a to create a sequence.

I start with a 0 here, so I can re-select by gv. If you start with a 1, you need to re-select by hand while omitting the first 1.

Use 2g Ctrl-a to use a step count of 2.


screen capture demonstrating how to generate a number sequence