Vim multiply column of numbers by series of numbers

Viewed 212

I have a column of numbers in my text file that looks like this:

10  1  -0.93
11  1  -0.93
12  1  -0.93
13  1  -0.93
...

(The first column of numbers is not the line number.)

I would like to replace the last column of numbers by multiplying each one by 0.1, 0.2, 0.3, etc. such that the result is

10  1  -0.093
11  1  -0.186
12  1  -0.279
13  1  -0.372
...

I know I can do math using the = register (is that the right terminology?), but I can't seem to figure out how to automate this. Please advise.

2 Answers

Assuming the 0.1/0.2/... correpond to "line number / 10", you can use

%s/\v(\S+)$/\=str2float(submatch(1)) * line('.') * 0.1

which captures the last column and return the result of "value * line_number * 0.1" using a
sub-replace-expression (see :help sub-replace-expression for more info on this).


If the values don't start on line 1 you could use a visual selection (to set line("'<")) and use line('.') - line("'<") + 1 to know where you are in the block. Then add the initial multiplier (0.1 here):

'<,'>s/\v(\S+)$/\=str2float(submatch(1)) * (line('.') - line("'<") + 1) * 0.1

This is much easier with awk (both to read and use) if you're ok making a copy of your data file that gets deleted immediately (i.e. don't use if your data file is massive).

Try:

: ! awk '{ $NF=$NF*(0.1 * NR); print}' data_file > tmp && mv tmp data_file 

Use ! to run the command outside of Vim in your terminal. Then for each line in your data_file, awk replaces the last column $NF with itself multiplied by (0.1 * NR) where NR is the row number. You can change this with whatever math logic you want. Then it prints the entire line with your modification.

Now, you just need to store this output in a temporary file tmp and then overwrite your data_file with the modified data, hence the mv command.

Vim will ask you to reload the file, which you should to load in the newly modified data.

Related