Jak zamienić tabulatory na spacje?

85

Czy można konwertować tabulatory na spacje, zachowując wyrównanie tekstu?

Po prostu zamiana działa tylko wtedy, gdy nie ma wiodących postaci.

ideasman42
źródło
Jeśli zainstalowałeś vim-faq , możesz tam uzyskać odpowiedź offline: :h vim-faqi wyszukać /tab characters. Trudno zapamiętać tag :h faq-14.16.
Hotschke

Odpowiedzi:

98

Możesz użyć :retabpolecenia. Od :help :retab

Zastąp wszystkie sekwencje białych <Tab>znaków zawierających nowe ciągami białych znaków, używając nowej podanej wartości tabstop. Jeśli nie określisz nowego rozmiaru tabstop lub jest on zerowy, Vim użyje bieżącej wartości 'tabstop'. [...] Po 'expandtab'włączeniu Vim zastępuje wszystkie tabulatory odpowiednią liczbą spacji.

Zauważ, że polecenie akceptuje zakres, więc możesz dokonać wizualnego wyboru, a następnie tylko :retabwybranych linii.

gilema
źródło
Chłodny! Działa szybko i prosto!
DenisKolodin
2
co powiesz na podanie przykładu?
Petr
23

Można jednak użyć :retab, jak wspomniano, spowoduje to zmianę wszystkich tabulatorów na spacje, nie tylko tabulatory na początku wiersza

Więc to (gdzie jest znak tabulacji):

if :; do
⇥echo "⇥hello"
end

zmienia się na (gdzie jest spacja):

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

Może to powodować nieoczekiwane skutki uboczne w niektórych scenariuszach, a to jeszcze większy problem przy zmianie spacji na tabulatory!

Tak więc napisałem małą funkcję zmiany tylko tabulatorów / spacji na początku wiersza:

" :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

W tej wersji musisz ręcznie określić expandtabw wywołaniu funkcji (tj. :call Retab(1)Zmienić tabulatory na spacje), ale możesz również zmodyfikować ją, aby przyjmowała bieżącą wartość &expandtab(jak to już ma miejsce &tabstop), tak jak to :retabrobi. (Zdarza mi się to określać ręcznie).

Martin Tournoij
źródło
6
Istnieje również odpowiedź na temat SO, która obejmuje tylko zmianę na początku linii. Warto połączyć ze względu na przejrzystość tego wyjaśnienia.
jalanb
Może ktoś wyjaśnić, co czyni nas aw if a:expandtabśredniej?
john cj
Wygląda też na to, że warunki są odwrócone (żart: D?). Jeśli masz set expandtabw .vimrc, a następnie autocmd BufWritePre * :call Retab(&expandtab)- wcięcie zostanie zmienione na tabulatory zamiast spacji.
John CJ
11

Vim udostępnia !retabpolecenie, które zastąpi wszystkie sekwencje <Tab>nowymi ciągami białych znaków za pomocą :set tabstop=2podanej nowej wartości tabstop (np. ), Ale wszystkie tabulacje wewnątrz ciągów można modyfikować (np. W programie C należy \ttego uniknąć)!

Alternatywnie możesz zmienić wszystkie tabulatory na spacje, używając następującego polecenia:

:%s/\t/  /g

lub zgodnie z sugestią @Shahbaz :

:%s/^\t\+/ g

Tak więc konwertowane są tylko tabulatory używane w wcięciach.

Wyjaśnienie:

  • %reprezentuje cały bufor / plik ( :help :%)
  • soznacza substytut ( :help sub-replace-special)
  • \tlub ^Ioznacza tab
  • - użyj tyle spacji, ile potrzebujesz na jedną kartę
  • g - oznacza globalny i przekształci wiele wystąpień kart w tym samym wierszu

Następnie skorygować wcięcia całego pliku, możesz spróbować: gg=G. Sprawdź: Ponowne wcięcie źle źle wciętego kodu, aby uzyskać więcej szczegółów.

Aby domyślnie używać spacji zamiast tabulatorów, musisz dodać do .vimrcpliku następujące ustawienia :

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 >>)

Alternatywnym rozwiązaniem jest użycie tidy


Związane z:

kenorb
źródło
1
Zrobiłbym przynajmniej %s/^\t\+/ gtak, aby konwertowane były tylko tabulatory używane w wcięciach. Ponadto gg=Gmoże być katastrofalny w przypadku języków takich jak python.
Shahbaz
3

Spróbuj użyć:

expand -t 4 input_filename output_filename

expandto narzędzie wiersza polecenia do konwersji tabulatorów na spacje, które można uruchomić z powłoki lub za pomocą :!expand.

Jest w POSIX, więc powinien być dostępny na większości systemów. unexpandnawiasem mówiąc, zrobi odwrotnie.

Ankit Shah
źródło
2
Co to jest expand?
muru
Rozwiń to wbudowane polecenie terminala do kopiowania znaku tabulacji na spacje. Szczegółowy opis znajdziesz w poniższym linku. computerhope.com/unix/uexpand.htm
Ankit Shah
2
Jeśli są to polecenia zewnętrzne, powinieneś o tym wspomnieć.
muru
Dodano dalszy opis. Proszę przejrzeć
Ankit Shah
5
Możesz także zrobić to :%!expand -t 4w vimie. Jeszcze lepiej, możesz również użyć bieżącej opcji szerokości przesunięcia: :exe '%!expand -t ' . &shiftwidth
EvergreenTree
1

Dla kompletności =można go również użyć do naprawy wcięć, po określeniu, że tabulatory są zastępowane spacjami. W trybie normalnym możesz to zrobić, pisząc :set expandtab. Następnie =można go użyć na dwa sposoby:

  • W trybie wizualnym jeden =naprawiałby wcięcia wybranych bloków kodu.
  • W trybie normalnym gg=Gnaprawiałby cały plik, w którym ggprzesuwa kursor na początek pliku, a następnie =jest stosowany i Gprzesuwa kursor na koniec pliku.

Odniesienie: link

Samuel Li
źródło
Zakłada się, że vim może poprawnie obliczyć bieżące wcięcie (może być inaczej) - także w przypadku plików nieustrukturyzowanych lub kodu napisanego w innym edytorze z nieco innymi regułami wcięcia.
ideasman42
Dzięki @ ideasman42; Dodałem do odpowiedzi, aby być bardziej kompletnym.
Samuel Li,