6

I have a file which content like this:

id      phone   name
x'1234' 12345   jack
x'4567' 45678   Jojo
x'7890'  89456  Dio
x'4591'  34872  joseph

and i want to parse it into like this:

id  phone   name
1   12345   jack
2   45678   Jojo
3    89456  Dio
4    34872  joseph

I know basic regular expression could replace all id to any string like this:

:%s/x'\(\w\+\)'/1/g

and it will become:

id  phone   name
1   12345   jack
1   45678   Jojo
1    89456  Dio
1    34872  joseph

How to replace id to an increment variable ?

mpromonet
  • 10,379
  • 42
  • 54
  • 85
a4fz067lu
  • 159
  • 2
  • 7

4 Answers4

9

Mind that you can use an expression as the replacement string in the substitute command (:s). When the replacement string starts with \= it is evaluated as an expression.

Here, one possible solution is

:let i=1 | g/^x'\d\+'/s//\=i/ | let i=i+1

It finds all occurrences (one per line) of the ^x'\d\+' pattern and replaces it with the value if i that is incremented each time the match is found. As has been noted in comments, the | is a part of the g replacing "code", as "| is used to execute more than one command at a time".

Another solution is using the line() command (taking into account that your file has a header top line, so you should actually subtract 1 from the value returned with line()):

%s/^x'\d\+'/\=line('.')-1/

The ^x'\d\+' regex matches

  • ^ - start of a line
  • x' - x' string
  • \d\+ - 1+ digits
  • ' - a ' char.

There are other interesting "increment number in regex" examples at the Using an expression in substitute command page:

  • Number all the lines in a file (insert line number followed by a tab):
    :%s/^/\=line('.')."\t"/
  • Number a range of lines (from line 10 to line 20):
    :10,20s/^/\=line('.')."\t"/
  • Number a range of lines sequentially starting from 1:
    :let counter=0|10,20g//let counter=counter+1|s/^/\=counter."\t"
  • Number all the paragraphs in range starting from 1 (assuming the paragraphs are separated by one or more blank lines):
    :let counter=0|1,20g/^$\n^\s*[^\s]/let counter=counter+1|+1s/^/\=counter."\t"
    Note: The above command does not work for the first paragraph in the file if there is no blank line above it.
Wiktor Stribiżew
  • 561,645
  • 34
  • 376
  • 476
  • 1
    This is a very nice answer. But the part of it that's really interesting is that `| let i=i+1` is part of the `g//` command, so executed for each of those lines. Visually, it doesn't look like that, at a first sight. Explaining that part would improve this answer. – filbranden Sep 02 '19 at 16:29
  • ohh, Thank you for your instruction and advice – a4fz067lu Sep 03 '19 at 01:51
7

one-shot

You can declare a variable as the other answer does, or:

:%s/^x'\([^']*\)'/\=line('.')-1/  

Replace the last 1 by the line number of your header (id, phone, name) line if it doesn't sit in line 1.

two steps

You can get followings just by replacing 1 into 0 in your codes

id  phone   name
0   12345   jack
0   45678   Jojo
0    89456  Dio
0    34872  joseph

Then you can move your cursor to the first id 0, then press:

ctrl-v G g ctrl-a

It will turn the 0s into a sequence from 1

  • ctrl-v: column mode
  • G : select the 1st col till the last line.
  • g+ctrl-a: add
Kent
  • 181,427
  • 30
  • 222
  • 283
0

Alternatively you could use use awk, column, & Vim's filter command.

:%!gawk 'NR>1 {$1=++i} 1' | column -t

Explanation:

  • :%!{cmd} will "filter" the range, % (whole file), through command {cmd}
  • gawk '..' will run an awk one-liner
  • NR>1 {..} will run a "block" for record number greater than 1 (skips header)
  • $1=++i will set the first field to variable i (pre-incremented)
  • 1 is short of {print} which will print out the row
  • {cmd1} | {cmd2} will pipe the output from command, {cmd1}, to the input of command {cmd2}
  • column -t will pretty print tabular looking data
Peter Rincker
  • 41,641
  • 9
  • 70
  • 96
0

My PatternsOnText plugin has (among many others) a :Renumber command for this; it simplifies the typical solution with :substitute and a replacement expression:

:%Renumber/^x'\d\+'/
Ingo Karkat
  • 161,022
  • 15
  • 231
  • 302