1

I am trying Vim capabilities and stuck with this task - addition the incrementing number to the end of each line.

Testing lines:

text
text
text
text
text

This command works partially:

:let n=1 | g/text/s/$/\=n/ | let n+=1

Result:

text1 
text2 
text3 
text4 
text5 

But I want to have space between the added numbers and the 'text'.

The adding of space ' ' before the \=doesn't work, because the \= should be in the beginning of substitute expression, else it is not parsed as an expression, but inserted literally - text =n:

:let n=1 | g/text/s/$/ \=n/ | let n+=1 ### doesn't work as expected

So, the questions:

  1. Is it possible to insert a string in the substitute expression?

Like this (the n is the variable):

s/$/string\=n/
s/$/'string'\=n/

or this:

s/$/\='string'n/
  1. Can I use multiple variables in the substitute expression by separating them from each other like in the bash?

Example:

s/$/\={var_1}{var_2}{var_3}/

3. Do you know more suitable/simple way for solving this task?

  • Does your buffer contain lines other than text? And do the text lines start on line 0? – DJMcMayhem Jan 17 at 19:31
  • @DJMcMayhem No, the buffer can contains any characters, the Python source code, for example. Also, this action can be required in the any line number. – MiniMax Jan 17 at 20:04
4

For your answer specifically, you could get around this by concatenating a space with the number, i.e.

:let n=1 | g/text/s/$/\=" ".n/ | let n+=1

If you want to do this to every line, there are some much shorter ways to do this. For example:

:%s/$/\=" ".line('.')

Or if you only want to number the lines matching "text", then either of these:

:%s/text/\=submatch(0)." ".line('.')
:%s/text\zs/\=" ".line('.')

You could even do the entire thing in normal mode. For example, you could do this:

gg<C-v>G$A 0<esc>gvg<C-a>

Where <C-v> means ctrl-v and <C-a> means ctrl-a

  • Thanks, it works. I was trying concatenation, but either without quotes, like s/$/\= .num/ or with quotes, but without dot: s/$/\=' 'n/ :). No, the line number can be random, as well as its content. The 'text' string were picked just for example. – MiniMax Jan 17 at 20:06
  • The second solution should be :%s/$/\=" ".line('.'), otherwise it replaces the text part to the line number, that is not what I want. Also, it numbers all lines in the buffer, empty lines included. – MiniMax Jan 17 at 20:15
  • @MiniMax Yes, good catch. I know that will do it to every line, but that was before I realized you only wanted specific lines. I'll leave that part up in case it can help someone else, but I'll edit it to be more clear about what it's doing. – DJMcMayhem Jan 17 at 20:20
  • 1
    The third one is beautiful. I knew about incrementing number by Ctrl-a, but didn't know g CTRL-A. It will be good to add description for gv and g CTRL-A to the answer for future. Note for others: the information about them located in the :h gv and :h Ctrl-a. – MiniMax Jan 17 at 20:40
1

Answer to the question №1:

:let n=1 | g/text/s/$/\=printf(" %d", n)/ | let n+=1

Result

text 1 
text 2 
text 3 
text 4 
text 5 

Answer to the question №2:

The substitute expression can contain multiple variables separated (concatenated) by dot . operator.

:let a = 'one'
:let b = 'two'
:let c = 'three'
:g/text/s/$/\=a.b.c/

Result

textonetwothree 
textonetwothree 
textonetwothree 
textonetwothree 
textonetwothree

If it is needed separate them by space, then do:

:g/text/s/$/\=' '.a.' '.b.' '.c/

or

:g/text/s/$/\=printf(' %s %s %s', a, b, c)/

Result

text one two three 
text one two three 
text one two three 
text one two three 
text one two three 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.