Let's say you have this (consider a Huge file with a pattern like this)
required string query = 1;
optional int32 pagenumber = 32;
optional optional result_per_page = 93;
optional Corpus corpus = 4;
required string url = 5;
And you want something like this
required string query = 1;
optional int32 pagenumber = 2;
optional optional result_per_page = 3;
optional Corpus corpus = 4;
required string url = 5;
The solution
gg
:let @r=0 | g/./ let @r=@r+1 | exec "norm t;ciw\<c-r>r"
We start by moving to the first line, after that we create a variable to store the number sequence we want.
We have a regex to match any character (which means it will match on all lines) /./
and we increment the register "r" let @r=@r+1
.
The normal command does the following
exec ................ execute the following
"norm ............... in normal mode
t; .................. jump til before ;
ciw ................. change inner word
\<c-r>r ............. now we insert the register "r"
In the "normal" part we use double quotes that allow us to use keystrokes like \<c-r>
, which means Ctrl-r
.
I stumbled upon a solution to a similar problem and how amazing it can be:
:let c=0 | g/\d\+\ze;$/ let c+=1 | s//\=c
In this case, we really need to specify the location of the numbers!
Another approach:
:let @a=1 | %s/\d\+\ze;$/\=(@a+setreg('a',@a+1))/g
In this case, we exchange the number /\d\+\ze;$/
for register a
and increase the register a
for the next match.
OBS: The idea for this article came from this post and possible I will change it to include more examples. in the original article, the author shows how to solve this problem using macros.
An elegant solution
Transform this
Irish Bands:
1. U2
2. The Cranberries
3. The Dubliners
English Bands:
1. Queen
2. Duran Duran
3. The Beatles
American Bands:
1. Nirvana
2. Blondie
3. The Doors
Into this:
Irish Bands:
1. U2
2. The Cranberries
3. The Dubliners
English Bands:
4. Queen
5. Duran Duran
6. The Beatles
American Bands:
7. Nirvana
8. Blondie
9. The Doors
Solution:
:let c=0 | g/^\d\+\ze\./ let c+=1 |s//\=c
Explanation:
let c=0|g/^\d\+\ze\./let c+=1|s//\=c
├─────┘ ├───────────┘├──────┘ ├─┘├─┘
│ │ │ │ └ with the current value of the counter (i.e. new number)
│ │ │ └ replace last used pattern (i.e. old number)
│ │ └ for every matched line, increment the counter
│ └ iterate over the lines starting with a number followed by a dot
└ initialize counter to 0
Som tips from vim wiki
" 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
Select the function with yip
, then run
:@0
:let i=1 | %s/\d\+\ze;$/\=Inc()
The option g:i
creates a "global" variable i
. The a:
stands for function argument.
let g:i += a:0 > 0 ? a:1 : 1
If the first argument `a:0` is bigger than zero use the second argument `a:1`, otherwise use one.
TIP: Understanding vimscript ternary operator
Let's start by creating a normal map to jump to a certain line if the user types a number before hitting Enter.
" 6 Enter goes to the line 6
nnoremap <expr> <cr> v:count == 0 ? "\<cr>" : "G"
nnoremap ............. normal map that does not allow recursion
<expr> ............... It means we are gonna use an expression
v:count .............. The count given for the last Normal mode command
== ................... compares things
Basically:
nnoremap <expr> "what evaluate" == "with what" ? true : false
If our evaluation is true it runs "true" otherwise it runs "false"
Top comments (0)