How to replace tabs with spaces?

Is it possible to convert tabs to spaces, while maintaining text alignment?

Simply replacing only works usefully when there are no leading characters.

• If you have installed vim-faq, you can get an offline answer there: :h vim-faq and search /tab characters. The hard to memorize tag is :h faq-14.16. – Hotschke Jul 23 at 7:55

You can use the :retab command. From :help :retab

Replace all sequences of white-space containing a <Tab> with new strings of white-space using the new tabstop value given. If you do not specify a new tabstop size or it is zero, Vim uses the current value of 'tabstop'. [...] With 'expandtab' on, Vim replaces all tabs with the appropriate number of spaces.

Note that the command accepts a range, so you can make a visual selection and then just :retab the selected lines.

• Cool! Works fast and simple! – DenisKolodin Nov 4 '16 at 9:59
• how about providing an example? – Petr May 15 '17 at 11:30

You can use :retab, as stated, however, this will change all tabs to spaces, not only tabs at the start of the line

So this (where ⇥ is a tab character):

if :; do
⇥echo "⇥hello"
end


gets changed to (where ␣ is a space character):

if :; do
␣␣echo "␣␣hello"
end


This can produce unexpected side-effects in some scenarios, and it's even more of an issue when changing spaces to tabs!

So, I wrote a little function to change only tabs/spaces at the start of the line:

" :retab changes *everything*, not just start of lines
fun! Retab(expandtab)
let l:spaces = repeat(' ', &tabstop)

" Replace tabs with spaces
if a:expandtab
silent! execute '%substitute#^\%(' . l:spaces . '\)\+#\=repeat("\t", len(submatch(0)) / &tabstop)#e'
" Replace spaces with tabs
else
silent! execute '%substitute#^\%(\t\)\+#\=repeat("' . l:spaces . '", len(submatch(0)))#e'
endif
endfun


With this version, you have to manually specify expandtab in the function call (ie. :call Retab(1) to change tabs to spaces), but you could also modify it to take the current value of &expandtab (as it already does with &tabstop) just like :retab does. (I happen to prefer to specify it manually).

• There is also an answer on SO which covers retabbing at start of line only. It is worth linking because of the clarity of that explanation. – jalanb Feb 6 '15 at 11:41
• Could somebody explain what does letter a in if a:expandtab mean? – john c. j. Feb 2 at 23:36
• Also, it seems the conditions are reversed (a joke :D?). If you have set expandtab in your .vimrc and then autocmd BufWritePre * :call Retab(&expandtab) - indentation will be changed to tabs, instead of spaces. – john c. j. Feb 2 at 23:50

Vim provides !retab command which will replace all sequences of <Tab> with new strings of white-space using the new tabstop (e.g. :set tabstop=2) value given, but all tabs inside of strings can be modified (e.g. in a C program, you should use \t to avoid this)!

So alternatively you can change all tabs into spaces using the following command:

:%s/\t/  /g


or as suggested by @Shahbaz:

:%s/^\t\+/ g


So only the tabs used in indentation are converted.

Explanation:

• % represents the entire buffer/file (:help :%)
• s stands for substitute (:help sub-replace-special)
• \t, or ^I stands for tab
• - use as many spaces as you need per one tab
• g - stands for global, and it'll convert multiple occurences of tabs in the same line

Then to correct indentation of the entire file, you may try: gg=G. Check: Re-indenting badly indented code for more details.

To use spaces by default instead of tabs, you need to add the following settings into your .vimrc file:

set tabstop=2     " (ts) width (in spaces) that a <tab> is displayed as
set expandtab     " (et) expand tabs to spaces (use :retab to redo entire file)
set shiftwidth=2  " (sw) width (in spaces) used in each step of autoindent (aswell as << and >>)


Alternative solution is to use tidy

Related:

• I would at least do %s/^\t\+/ g so that only the tabs used in indentation are converted. Also, gg=G could be catastrophic with languages like python. – Shahbaz Mar 4 '17 at 15:49

Try using:

expand -t 4 input_filename output_filename


expand is a command-line tool to convert tabs to spaces, which you can run from a shell or with :!expand.

It's in POSIX so it should be available on most systems. unexpand will do the reverse, by the way.

• What is expand? – muru Feb 1 '16 at 12:47
• Expand is an inbuilt terminal command to copy tab character to spaces. Please find a detailed discription in the following link. computerhope.com/unix/uexpand.htm – Ankit Shah Feb 1 '16 at 13:48
• If these are external commands, you should mention that. – muru Feb 1 '16 at 13:49
• Further description added. Please review – Ankit Shah Feb 1 '16 at 13:52
• You could also just do :%!expand -t 4 inside of vim. Better yet, you could also use the current shift width option: :exe '%!expand -t ' . &shiftwidth – EvergreenTree Feb 1 '16 at 21:29

For completeness, = could also be used to fix indentations, after you have specified that tabs are replaced with spaces. In normal mode, you can do so by typing :set expandtab. Then = could be used in two ways:

• In Visual mode, a single = would fix indentations of selected code blocks.
• In normal mode, gg=G would fix the entire file, where gg moves the cursor to the beginning of the file, then = is applied, and G moves the cursor to the end of the file.