ericblackfoot
ericblackfoot

Reputation: 53

How to append each line from 11-20 to each line from 1-10 in VIM

I have a file in which first 10 lines are the columns of a table and the rest 10 lines are the values of each column.

How can I use norm in VIM to append the values after each column names like this:

column1
...
column10
value1
...value10

-->

column1: value1
...
column10: value10

It is a little similar with this(Vim - Copy Nth word of each line, from line 10-100, to end of line), but I don't know how to go to line 1:10 and append the copied lines.

Any idea will be appreciated!

Upvotes: 3

Views: 143

Answers (2)

Marth
Marth

Reputation: 24832

Fairly naive and crude way to do this, but:

:1,10norm! 10j0d$10kA: ^[p

Explanation:

  • 1,10norm!: for lines 1 to 10, do the following (the ! means any custom mapping you have will be ignored, thanks to D. Ben Knoble for reminding of this):
  • 10j: move down 10 lines
  • 0d$: delete the whole line (not including newline)
  • 10k: move back up 10 lines
  • A:: append (at the end of the line) ': ' (note the trailing space)
  • ^[: input escape character, going back to normal mode. This (^[) is a single character and is inputted by typing Ctrl-v then escape, not by typing ^[.
  • p: paste the line deleted in step 3

Another (copy-pastable) way, (ab)using the substitute command:

:1,10s/\v(.*)\ze(.*\n){10}(.*)/\1: \3/ | 11,20d

which does:

  • 1,10s/: for lines 1 to 10, execute the following substitution:
  • \v: use very-magic regex mode (see :help \v)
  • (.*): capture the entire current line (eg column1)
  • \ze: signal the end of the match. This way everything read (and captured) afterwards will not be affected (but can still be read)
  • (.*\n){10}: skip 10 (including current) lines, ie skip selector to 10 lines below
  • (.*): capture the line (eg value1)
  • /: end the 'select' part of the substitute command
  • \1: \3: replace with captured groups (eg column1: value1)
  • |: command separator
  • 11,20d: delete lines 11 to 20

Upvotes: 4

filbranden
filbranden

Reputation: 8908

Use blockwise-visual mode to perform the operations.

You can enter visual block mode with Ctrl-V and it allows you to select and operate on columns. It also allows you to perform the same action on a block, which you can use to add the : to the lines with the column names.

I'll use normal Vim syntax for keystrokes in my examples, <C-v> means Ctrl-V.

Start by deleting the values into the default register, using a visual block:

11G<C-v>9j$d

Then Add the : to the column lines, also using a visual block:

1G<C-v>9j$A: <Esc>

Then add some more spaces to the first line, to ensure there's room for all the column names to fit:

A    <Esc>

Finally, put the visual block at the end of the first line:

$p

It will actually put it on all lines all the way to the end.

This is slightly different from what you specified, since the values are all aligned on the same column. If you want different spacing, you can perhaps use a :s operation to fix spacing.

10:s/:  */: /<cr>

Depending on where you pasted (if some column names had more trailing spaces than the first one), you might have some trailing spaces after the pasted values to fix as well, but that should be easy to do using a similar procedure.

Visual block operations are really powerful, it's a great feature to learn and keep in your "toolbox" in Vim. They're really handy with this kind of problem where thinking in "columns" makes the most sense.

Upvotes: 1

Related Questions