Jak przekonwertować spacje na tabulatory w Vimie lub Linuksie?


192

Przejrzałem kilka pytań na temat przepełnienia stosu, aby przekonwertować spacje na tabulatory bez znajdowania tego, czego potrzebuję. Wydaje się, że jest więcej pytań na temat konwersji tabulatorów na spacje, ale staram się zrobić odwrotnie.

W VimPróbowałem :retabi :retab!bez powodzenia, ale wydaje mi się, że i tak są przeznaczone do przechodzenia od zakładek do spacji.

Próbowałem obu expandi unexpandw wierszu polecenia bez powodzenia.

Oto plik, o którym mowa:

http://gdata-python-client.googlecode.com/hg-history/a9ed9edefd61a0ba0e18c43e448472051821003a/samples/docs/docs_v3_example.py

Jak przekonwertować spacje wiodące na tabulatory za pomocą Vimpowłoki lub powłoki?


W komentarzu @ Matta, który jest teraz usunięty, sed "s/ +/`echo -e '\t'`/g" < input.py > output.pypojawia się pierwszy przykład ( ) do konwersji wszystkich spacji, a nie tylko spacji wiodących. W drugim przykładzie ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py) zamienia tylko pierwszą spację w każdym wierszu tabulatorem i pozostawia resztę.
cwd


Nie znalazłem odpowiedzi na wszystkie / wiele plików , więc napisałem swój własny: stackoverflow.com/a/44581474/1115187 . Z find, awki blackjack (zbyt długi, aby pozostawić go w komentarzach, choć)
maxkoryukov

Odpowiedzi:


316

Używając Vima do rozszerzenia wszystkich wiodących pól (szerszych niż 'tabstop'), miałeś rację, retabale najpierw upewnij się, że 'expandtab'został zresetowany ( :verbose set ts? et?jest twoim przyjacielem). retabma zakres , więc zwykle określam %jako „cały plik”.

:set tabstop=2      " To match the sample file
:set noexpandtab    " Use tabs, not spaces
:%retab!            " Retabulate the whole file

Przed zrobieniem czegoś takiego (szczególnie z plikami Pythona!) Zwykle ustawiam 'list', aby widzieć białe znaki i zmieniać.

Mam następujące mapowania w moim.vimrc do tego:

nnoremap    <F2> :<C-U>setlocal lcs=tab:>-,trail:-,eol:$ list! list? <CR>

2
oto jak mam go do pracy, nie wiem, co jest konieczne, a co nie, a przy okazji nie wiem co „%” przed reatab robi: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
CWD

2
Zaktualizowałem swoją odpowiedź, aby zawierała wyjaśnienie, dlaczego używam %. Mapowanie F2 jest dokładnie tak, jak zostało wpisane .
Johnsyweb

7
Dla tego konkretnego pliku chciałbym po prostu::set noet ts=2 |%retab!
Johnsyweb

1
@Johnsyweb, aby być uczciwym, myliłem się: :%retab!nadal działa. Byłem zmieszany z ==, itp, które nie respektują ustawienia preserveindent.
Unk

1
Aby przekonwertować plik coffeescript ze spacji na tabulatory, podążyłem za odpowiedzią @ Johnsyweb (w tym dodatek do pliku .vimrc), ale zamiast tego:set tabstop=4
Mikeumus

38

1 - Jeśli masz spacje i chcesz tabulatory.

Najpierw musisz zdecydować, ile spacji będzie miało jedną kartę. To powiedziawszy, załóżmy, że masz linie z wiodącymi 4 spacjami lub 8 ... Niż zdajesz sobie sprawę, że prawdopodobnie chcesz, aby tabulator miał 4 spacje. Teraz dzięki tym informacjom wykonujesz:

:set ts=4
:set noet
:%retab!

Tutaj jest problem! Ta sekwencja poleceń wyszuka cały tekst, a nie tylko spacje na początku wiersza. Oznacza to, że ciąg: "Hey,␣this␣␣␣␣is␣4␣spaces"stanie się "Hey,␣this⇥is␣4␣spaces", ale nie jest! jest to zakładka!

Aby rozwiązać ten mały problem, polecam searchzamiast retab.

:%s/^\(^I*\)␣␣␣␣/\1^I/g

To wyszukiwanie sprawdzi w całym pliku wszelkie wiersze zaczynające się od dowolnej liczby tabulatorów, po których następują 4 spacje, i zastąpi je dowolną liczbą znalezionych tabulatorów plus jedną.

To niestety nie będzie działać od razu!

Na początku plik będzie miał linie zaczynające się od spacji. Wyszukiwanie przekształci wtedy tylko pierwsze 4 spacje w tabulatory i niech następujące ...

Musisz powtórzyć polecenie. Ile razy? Dopóki nie dostaniesz pattern not found. Nie mogę jeszcze wymyślić sposobu na automatyzację tego procesu. Ale jeśli to zrobisz:

`10@:`

Prawdopodobnie skończyłeś. To polecenie powtarza ostatnie wyszukiwanie / zamianę 10 razy. Jest mało prawdopodobne, że twój program będzie miał tyle wcięć. Jeśli tak, po prostu powtórz ponownie @@.

Teraz, aby uzupełnić odpowiedź. Wiem, że prosiłeś o coś przeciwnego, ale nigdy nie wiesz, kiedy musisz coś cofnąć.

2 - Masz tabulatory i chcesz spacji.

Najpierw zdecyduj, na ile spacji chcesz przekonwertować karty. Powiedzmy, że chcesz, aby każda karta miała 2 spacje. Następnie wykonujesz:

:set ts=2
:set et
:%retab!

Miałoby to ten sam problem z łańcuchami. Ale ponieważ jest to lepszy styl programowania, aby nie używać twardych tabulatorów wewnątrz ciągów, tak naprawdę robisz tutaj dobrą rzecz. Jeśli naprawdę potrzebujesz tabulatora wewnątrz ciągu, użyj \t.


Wydaje się niezwykle rzadkim stanem wyścigowym. W każdym razie stwórz funkcję akceptującą wybór zakresu wizualnego i iteruj funkcję wyszukiwania, dopóki nie zostanie znalezione dopasowanie, myślę, że byłaby to mądrzejsza i przydatniejsza odpowiedź.
albfan

Tak, czy tamto. Jeśli chcesz bardziej ostatecznego rozwiązania, możesz użyć funkcji. Tak czy ex commandinaczej , zawsze dobrze jest wiedzieć, jak to zrobić w , ponieważ byłoby to tym, co jest w funkcji. I nie, to nie jest rzadkie. Musisz tylko mieć ciągi ze spacjami, aby mieć bałagan. Wcale nie rzadkie. Jestem tam Dzięki za komentarz.
Dr Beco

Wyjaśnij, dlaczego / g nie wystarcza do przekonwertowania wszystkich grup po 4 w każdej linii kolejnych spacji na tabulatory, zamiast konieczności wielokrotnego wyszukiwania.
Bjartur Thorlacius

Cześć @BjarturThorlacius, problem polega na tym, że jeśli usuniesz ^symbol, aby rozpocząć wyszukiwanie od początku linii, ryzykujesz zmianę spacji w łańcuchach. Z ^gwarancją, że zmieniasz tylko spacje i tabulatory od początku linii, a tym samym wcięcie. Poza tym, jeśli jesteś pewien, że możesz zrobić wszystko naraz, usuń ^i uruchom tylko raz z::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr Beco

14
:%s/\(^\s*\)\@<=    /\t/g

Tłumaczenie: Wyszukaj każdą instancję 4 kolejnych spacji (po znaku =), ale tylko wtedy, gdy cała linia do tego punktu jest spacją (używa to potwierdzenia zerowej szerokości, \@<=). Zastąp każde znalezione wystąpienie znakiem tabulacji.


1
Jedyne rozwiązanie, które działało na powiększenie 1 spacji do 1 tab , ale strzeż się Unicode w odpowiedzi, właśnie użyłem :%s/\(^\s*\)\@<= /\t/g- umieść odpowiednią liczbę spacji (aby przekonwertować 4 spacje na 1 tab, wstaw 4 spacje) zaraz po<=
Orwellophile

5

Zmienia wszystkie spacje na tabulator:% s / \ s / \ t / g


Właśnie tego potrzebowałem. Dzięki. Jedyną zmianą, którą musiałem wprowadzić, było zastąpienie co 4 spacje znakiem tabulacji zamiast robienia każdej pojedynczej spacji.
Anonimowa osoba,

3

Linux: z unexpand(i expand)

Oto bardzo dobre rozwiązanie: https://stackoverflow.com/a/11094620/1115187 , głównie dlatego, że używa * nix-utilities:

  1. nierozwinięcie - spacje -> tabulatory
  2. rozwiń - tabulatory -> spacje

Linux: niestandardowy skrypt

Moja oryginalna odpowiedź

Fragment Bash do zamiany wcięcia 4- spacji (są dwa {4}w skrypcie) na tabulatory we wszystkich .pyplikach w ./appfolderze (rekurencyjnie):

find ./app -iname '*.py' -type f \
    -exec awk -i inplace \
    '{ match($0, /^(( {4})*)(.*?)$/, arr); gsub(/ {4}/, "\t", arr[1]) }; { print arr[1] arr[3] }' {} \; 

Nie modyfikuje 4-spacji na środku lub na końcu.

Został przetestowany pod Ubuntu 16.0x i Linux Mint 18


0

W moim przypadku miałem wiele spacji (pola były oddzielone jedną lub więcej spacjami), które chciałem zastąpić tabulatorem. Zrobili to:

:% s/\s\+/\t/g

0

Jeśli zainstalowano coreutils GNU, należy rozważyć %!unexpand --first-onlyczy na kartach 4-przestrzeni, należy rozważyć %!unexpand -t 4 --first-only( --first-onlywystępuje tylko w przypadku, gdy zostały przypadkowo powołując unexpandsię --all).

Zauważ, że zastąpi to tylko spacje poprzedzające określone tabulatory, a nie spacje, które za nimi podążają; nie zobaczysz żadnej różnicy wizualnej w vimie, chyba że będziesz wyświetlał zakładki bardziej dosłownie; na przykład moje ~/.vimrczawiera set list listchars=tab:▸┈(podejrzewam, że dlatego myślałeś, unexpandże nie działa).


0

Aby użyć Vima do zmiany zestawu plików (np. Wszystkich plików * .ts w hierarchii katalogów) od powiedzmy 2 spacje do 4 spacji, możesz wypróbować to z wiersza poleceń:

find . -name '*.ts' -print0 | xargs -0 -n1 vim -e '+set ts=2 noet | retab! | set ts=4 et | retab | wq'

Działa to w findcelu przekazania wszystkich pasujących plików do xargs(opcja -print0 w find działa z opcją -0 dla xargs w celu obsługi plików z / spacjami w nazwie).

xargs uruchamia vim w trybie ex ( -e) na każdym pliku, wykonując podaną komendę ex, która jest w rzeczywistości kilkoma komendami, aby zmienić istniejące początkowe spacje na tabulatory, zresetować tabulator i przestawić tabulatory z powrotem na spacje, a na koniec zapisać i wyjść.

Uruchamianie w trybie ex zapobiega temu: Vim: Warning: Input is not from a terminaldla każdego pliku.


-1

Prosty skrypt w języku Python:

import os

SOURCE_ROOT = "ROOT DIRECTORY - WILL CONVERT ALL UNDERNEATH"

for root, dirs, files in os.walk(SOURCE_ROOT):
    for f in files:
        fpath = os.path.join(root,f)
        assert os.path.exists(fpath)
        data = open(fpath, "r").read()
        data = data.replace("    ", "\t")
        outfile = open(fpath, "w")
        outfile.write(data)
        outfile.close()

Jeden wielki problem: ten fragment zastępuje wszystkie 4 spacje, nie tylko wcięcia (na początku linii)
maxkoryukov

a po drugie: filtr plików nie jest zaimplementowany
maxkoryukov
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.