mathematical.coffee
mathematical.coffee

Reputation: 56915

How to pad all lines with spaces to a fixed width in Vim (perhaps using sed, awk, etc.)?

How can I pad each line of a file to a certain width (say, 63 characters), padding with spaces if need be?

For simplicity, let’s assume that all lines are guaranteed to be less than 63 characters.

I use Vim and would prefer a way to do it there, where I can select the lines I wish to apply the padding to, and run some sort of a printf %63s current_line command.

However, I’m certainly open to using sed, awk, or some sort of linux tool to do the job too.

Upvotes: 26

Views: 18456

Answers (8)

ib.
ib.

Reputation: 28954

In Vim, I would use the following command:

:%s/$/\=repeat(' ',64-virtcol('$'))

The use of the virtcol() function here, as opposed to the col() one, is guided by the necessity to properly handle tab characters as well as multibyte non-ASCII characters that might occur in the text.)


To compute the length of the longest line in the buffer (plus 1) — to be used in place of 64 — one can use the following command:

:let m = max(map(range(1, line('$')), 'virtcol([v:val,"$"])'))

The range of lines can be narrowed, if necessary. For example, to do the same for the visually selected lines, one can provide map() with the range(line("'<"), line("'>")) argument, instead (see :help line(), :help '<). (Notice that in the latter case, to run the command interactively while in Visual mode, one will need to delete the '<,'> prefix that Vim will automatically put in the command line once : is typed.)

To do both steps in a single command invocation, one can join the two commands with |. For instance, to pad visually selected lines (or the lines that were in the last Visual selection), run:

:let m=max(map(range(line("'<"),line("'>")),'virtcol([v:val,"$"])')) | '<,'>s/$/\=repeat(' ',m-virtcol('$'))

If used frequently, this combined command can can be bound to a key mapping. Here is an example implementation of a Visual-mode key mapping to be added to the .vimrc file:

vnoremap <silent> <leader><bar> :call RightPadLines(' ', +0)<cr>
func! RightPadLines(char, extra) range
    let m = max(map(range(a:firstline, a:lastline), 'virtcol([v:val, "$"])'))
    let m += a:extra
    sil exec $'{a:firstline},{a:lastline}' 's/$/\=repeat(a:char, m-virtcol("$"))'
endfunc

The keyboard shortcut here is the leader key (see :help mapleader) followed by the | key, but, of course, any combination can be used instead.

Upvotes: 15

Chris Koknat
Chris Koknat

Reputation: 3451

Another Perl solution:

$ perl -lne 'printf "%-63s\n", $_' file

Upvotes: 2

jfg956
jfg956

Reputation: 16750

With sed, without a loop:

$ sed -i '/.\{63\}/!{s/$/                                                                /;s/^\(.\{63\}\).*/\1/}' file

Be sure to have enough spaces in the 1st substitution to match the number of space you want to add.

Upvotes: 2

thurmanukyalur
thurmanukyalur

Reputation: 21

It looks like you are comfortable using vim, but here is a pure Bash/simple-sed solution in case you need to do it from the command line (note the 63 spaces in the sed substitution):

$ sed 's/$/                                                               /' yourFile.txt |cut -c 1-63

Upvotes: 2

potong
potong

Reputation: 58430

This might work for you:

$ sed -i ':a;/.\{63\}/!{s/$/ /;ba}' file

or perhaps more efficient but less elegant:

$ sed -i '1{x;:a;/.\{63\}/!{s/^/ /;ba};x};/\(.\{63\}\).*/b;G;s//\1/;y/\n/ /' file

Upvotes: 3

glenn jackman
glenn jackman

Reputation: 246827

Just for fun, a Perl version:

$ perl -lpe '$_ .= " " x (63 - length $_)'

Upvotes: 3

GambitGeoff
GambitGeoff

Reputation: 639

$ awk '{printf "%-63s\n", $0}' testfile > newfile

Upvotes: 29

kev
kev

Reputation: 161674

Vim

:%s/.*/\=printf('%-63s', submatch(0))

Upvotes: 38

Related Questions