Wie kann ich in Vim oder Linux Leerzeichen in Tabulatoren konvertieren?


189

Ich habe einige Fragen zum Stapelüberlauf durchgesehen, um zu erfahren, wie Leerzeichen in Tabulatoren konvertiert werden können, ohne zu finden, was ich benötige. Es scheint mehr Fragen zu geben, wie Tabulatoren in Leerzeichen konvertiert werden, aber ich versuche das Gegenteil zu tun.

In Vimich versucht habe :retabund :retab!ohne Glück, aber ich glaube , die sind eigentlich für sowieso von Tabs zu Leerzeichen gehen.

Ich habe beide expandund unexpandan der Eingabeaufforderung ohne Glück versucht .

Hier ist die betreffende Datei:

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

Wie kann ich führende Leerzeichen mithilfe von entweder Vimoder der Shell in Tabulatoren konvertieren ?


In @ Matts Kommentar, der jetzt gelöscht wird, sed "s/ +/`echo -e '\t'`/g" < input.py > output.pyscheint das erste Beispiel ( ) alle Leerzeichen zu konvertieren, nicht nur führende Leerzeichen. Im zweiten Beispiel ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py) wird nur das erste Leerzeichen in jeder Zeile durch eine Registerkarte ersetzt und der Rest verbleibt.
CWD

Gegenteil verwandt: Wie ersetze Tabulatoren durch Leerzeichen? bei Vim SE
Kenorb

Ich habe nicht für alle / viele Dateien eine Antwort gefunden , daher habe ich meine eigene geschrieben: stackoverflow.com/a/44581474/1115187 . Mit find, awkund Blackjack (zu lange es in den Kommentaren zu verlassen, obwohl)
maxkoryukov

Antworten:


312

Wenn Sie Vim verwenden, um alle führenden Bereiche zu erweitern (breiter als 'tabstop'), haben Sie zu Recht verwendet, retababer zuerst sichergestellt, dass sie 'expandtab'zurückgesetzt werden ( :verbose set ts? et?ist Ihr Freund). retabnimmt einen Bereich , so spezifiziere ich normalerweise% "die gesamte Datei" an.

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

Bevor ich so etwas mache (besonders mit Python-Dateien!), Setze ich normalerweise 'list' , so dass ich sehe das Leerzeichen und ändern.

Ich habe die folgende Zuordnung in meinem.vimrc dafür:

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

2
hier ist , wie ich es an der Arbeit bekam, nicht sicher , was notwendig ist und was nicht, und btw ich nicht weiß , was das „%“ vor reatab tut: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
CWD

2
Ich habe meine Antwort aktualisiert, um eine Erklärung zu enthalten, warum ich sie verwende %. Das F2-Mapping entspricht genau der Eingabe .
Johnsyweb

7
Für diese bestimmte Datei würde ich nur tun::set noet ts=2 |%retab!
Johnsyweb

1
@ Johnsyweb um fair zu sein, ich habe mich geirrt: :%retab!funktioniert immer noch. Ich war verwirrt mit ==, etc , die tut die preserveindent Einstellung respektieren.
Unk

1
Um eine Coffeescript-Datei von Leerzeichen in Tabulatoren zu konvertieren, folgte ich der Antwort von @ Johnsyweb (einschließlich der Hinzufügung zur .vimrc-Datei), aber stattdessen mit einem:set tabstop=4
Mikeumus

38

1 - Wenn Sie Leerzeichen haben und Tabulatoren möchten.

Zunächst müssen Sie entscheiden, wie viele Leerzeichen eine einzelne Registerkarte haben soll. Angenommen, Sie haben Zeilen mit führenden 4 Leerzeichen oder 8 ... Dann stellen Sie fest, dass ein Tab wahrscheinlich 4 Leerzeichen enthalten soll. Mit diesen Informationen tun Sie Folgendes:

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

Hier gibt es ein Problem! Diese Befehlsfolge sucht nach Ihrem gesamten Text, nicht nur nach Leerzeichen am Zeilenanfang. Das bedeutet, dass eine Zeichenfolge wie: "Hey,␣this␣␣␣␣is␣4␣spaces"wird "Hey,␣this⇥is␣4␣spaces", aber es ist nicht! Es ist ein Tab!.

Um dieses kleine Problem zu lösen, empfehle ich searchstattdessen a retab.

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

Bei dieser Suche wird in der gesamten Datei nach Zeilen gesucht, die mit einer beliebigen Anzahl von Tabulatoren beginnen, gefolgt von 4 Leerzeichen, und durch die Anzahl der gefundenen Tabulatoren plus einer ersetzt.

Dies wird leider nicht sofort ausgeführt!

Die Datei enthält zunächst Zeilen, die mit Leerzeichen beginnen. Die Suche konvertiert dann nur die ersten 4 Leerzeichen in eine Registerkarte und lässt die folgenden ...

Sie müssen den Befehl wiederholen. Wie oft? Bis du eine bekommst pattern not found. Ich kann mir noch keine Möglichkeit vorstellen, den Prozess zu automatisieren. Aber wenn Sie dies tun:

`10@:`

Sie sind wahrscheinlich fertig. Dieser Befehl wiederholt das letzte Suchen / Ersetzen zehnmal. Es ist unwahrscheinlich, dass Ihr Programm so viele Einrückungen hat. Wenn ja, wiederholen Sie einfach noch einmal @@.

Nun, nur um die Antwort zu vervollständigen. Ich weiß, dass Sie nach dem Gegenteil gefragt haben, aber Sie wissen nie, wann Sie Dinge rückgängig machen müssen.

2 - Sie haben Tabulatoren und möchten Leerzeichen.

Entscheiden Sie zunächst, in wie viele Leerzeichen Ihre Registerkarten konvertiert werden sollen. Nehmen wir an, Sie möchten, dass jede Registerkarte 2 Leerzeichen enthält. Sie tun dann:

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

Dies hätte das gleiche Problem mit Zeichenfolgen. Aber da es ein besserer Programmierstil ist, keine harten Tabulatoren in Strings zu verwenden, tun Sie hier tatsächlich etwas Gutes. Wenn Sie wirklich eine Registerkarte in einer Zeichenfolge benötigen, verwenden Sie \t.


Scheint eine äußerst seltene Rennbedingung zu sein. Erstellen Sie auf jeden Fall eine Funktion, die die Auswahl des Sichtbereichs akzeptiert, und wiederholen Sie die Suchfunktion, bis keine Übereinstimmung mehr gefunden wird. Ich denke, das wäre eine klügere und nützlichere Antwort.
Albfan

Ja oder so. Wenn Sie eine endgültigere Lösung wünschen, können Sie eine Funktion verwenden. Wie auch immer, es ist immer gut zu wissen, wie man das macht ex command, denn das wäre das, was sich in der Funktion befindet. Und nein, es ist nicht selten. Sie müssen nur Zeichenfolgen mit Leerzeichen haben, um ein Durcheinander zu haben. Gar nicht selten. Ich bin da. Danke für den Kommentar.
Dr. Beco

Bitte erläutern Sie, warum / g nicht ausreicht, um alle 4er-Gruppen in jeder Zeile aufeinanderfolgender Leerzeichen in Tabulatoren umzuwandeln, anstatt die Suche mehrmals ausführen zu müssen.
Bjartur Thorlacius

Hallo @BjarturThorlacius, das Problem ist, dass Sie beim Entfernen des ^Symbols, um die Suche am Zeilenanfang zu starten, das Risiko eingehen, Leerzeichen innerhalb von Zeichenfolgen zu ändern. Mit der ^Sie garantieren, dass Sie seit Beginn der Zeile nur Leerzeichen und Tabulatoren ändern, also Einrückung. Wenn Sie sicher sind, dass es in Ordnung ist, alles auf einmal zu tun, entfernen Sie das ^und führen Sie es nur einmal aus mit::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr. Beco

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

Übersetzung: Suchen Sie nach jeder Instanz von 4 aufeinanderfolgenden Leerzeichen (nach dem Zeichen =), jedoch nur, wenn die gesamte Zeile bis zu diesem Punkt ein Leerzeichen ist (dies verwendet die Behind-Behauptung mit der Breite Null \@<=). Ersetzen Sie jede gefundene Instanz durch ein Tabulatorzeichen.


1
Die einzige Lösung, die funktioniert hat, um 1 Leerzeichen auf 1 Tab zu erweitern , aber Vorsicht vor dem Unicode in der Antwort. Ich habe gerade verwendet :%s/\(^\s*\)\@<= /\t/g- setzen Sie die entsprechende Anzahl von Leerzeichen (um 4 Leerzeichen in 1 Tabulator umzuwandeln, setzen Sie 4 Leerzeichen ein) direkt nach dem<=
Orwellophile

5

Ändert alle Leerzeichen in Tabulator:% s / \ s / \ t / g


Genau das brauchte ich. Vielen Dank. Die einzige Änderung, die ich vornehmen musste, war, alle 4 Felder durch eine Registerkarte zu ersetzen, anstatt jedes einzelne Feld zu machen.
Anonyme Person

3

Linux: mit unexpand(und expand)

Hier ist eine sehr gute Lösung: https://stackoverflow.com/a/11094620/1115187 , hauptsächlich, weil * nix-Dienstprogramme verwendet werden:

  1. nicht erweitern - Leerzeichen -> Tabulatoren
  2. Erweitern - Tabulatoren -> Leerzeichen

Linux: Benutzerdefiniertes Skript

Meine ursprüngliche Antwort

Bash-Snippet zum Ersetzen von Einrückungen mit 4 Leerzeichen (es gibt zwei {4}im Skript) durch Tabulatoren in allen .pyDateien im ./appOrdner (rekursiv):

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

Es werden keine 4 Leerzeichen in der Mitte oder am Ende geändert.

Wurde unter Ubuntu 16.0x und Linux Mint 18 getestet


0

In meinem Fall hatte ich mehrere Leerzeichen (Felder wurden durch ein oder mehrere Leerzeichen getrennt), die ich durch eine Registerkarte ersetzen wollte. Folgendes hat es getan:

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

0

Wenn Sie GNU coreutils installiert ist , prüfen %!unexpand --first-onlyoder für 4-Raum - Tabs, betrachten %!unexpand -t 4 --first-only( --first-onlyvorhanden ist nur, wenn Sie aus Versehen wurden Aufruf unexpandmit --all).

Beachten Sie, dass dadurch nur die Leerzeichen vor den vorgeschriebenen Tabulatoren ersetzt werden, nicht die darauf folgenden Leerzeichen. Sie werden keinen visuellen Unterschied in vim sehen, es sei denn, Sie zeigen Registerkarten wörtlicher an. Zum Beispiel ~/.vimrcenthält meine set list listchars=tab:▸┈(ich vermute, das ist der Grund, warum Sie dachten, dass unexpandes nicht funktioniert hat).


0

Um mit Vim eine Reihe von Dateien (z. B. alle * .ts-Dateien in einer Verzeichnishierarchie) von beispielsweise 2 bis 4 Leerzeichen neu zu erstellen, können Sie dies über die Befehlszeile versuchen:

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

Damit werden findalle übereinstimmenden Dateien an übergebenxargs (die Option -print0 bei find funktioniert mit der Option -0 an xargs, um Dateien mit Leerzeichen im Namen zu verarbeiten).

xargs führt vim im Ex-Modus aus (-e ) für jede Datei aus, wobei der angegebene ex-Befehl ausgeführt wird, bei dem es sich tatsächlich um mehrere Befehle handelt, um die vorhandenen führenden Leerzeichen in Tabulatoren zu ändern, den Tabulator zurückzusetzen und die Tabulatoren wieder in Leerzeichen zu ändern und schließlich zu speichern und zu beenden.

Das Ausführen im Ex-Modus verhindert dies: Vim: Warning: Input is not from a terminalfür jede Datei.


-1

Einfaches Python-Skript:

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

Ein großes Problem: Dieses Snippet ersetzt alle 4 Leerzeichen, nicht nur Einrückungen (am Anfang der Zeile)
maxkoryukov

und der zweite:
Dateifilter
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.