sed wandle 4 Felder in 2 um

14

Wie wandelt man mit 4 Leerzeichen in 2 Leerzeichen um sed? Ist es möglich?

Ich habe das gefunden, aber es konvertiert Tab in Leerzeichen:

sed -r ':f; s|^(\t*)\s{4}|\1\t|g; t f' file

chrisjlee
quelle

Antworten:

13

Das von Ihnen veröffentlichte Skript konvertiert 4 * n Leerzeichen in n Tabulatoren, nur wenn diesen Leerzeichen nur Tabulatoren vorangestellt sind.

Wenn Sie 4 Leerzeichen durch 2 Leerzeichen ersetzen möchten, aber nur in Einrückung, während dies mit sed möglich ist, empfehle ich stattdessen Perl.

perl -pe 's{^((?: {4})*)}{" " x (2*length($1)/4)}e' file

In sed:

sed -e 's/^/~/' -e ': r' -e 's/^\( *\)~    /\1  ~/' -e 't r' -e 's/~//' file

Vielleicht möchten Sie indentstattdessen verwenden.

Gilles 'SO - hör auf böse zu sein'
quelle
Ich bekamNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
Eddygeek
1
@eddygeek Oh ja, das und ein paar andere Bugs. Ich habe das GobbledyGook durch den aktuellen Perl-Code ersetzt.
Gilles 'SO- hör auf böse zu sein'
5

Funktioniert der einfache Weg nicht:

sed -r 's/ {4}/  /g'

Wenn nicht, posten Sie eine Eingabe, bei der dies fehlschlägt.

Thor
quelle
1
Dies ist nicht auf den Zeilenanfang beschränkt. Wenn Sie es dort verankern, funktioniert es nicht für mehrere Übereinstimmungen. Wir sind also unter unix.stackexchange.com/a/375200/259620 zu finden .
Geek-Merlin
Dies funktioniert nicht, wenn Sie eine Kombination aus 2 Leerzeichen und 4 Leerzeichen haben, da zwei Einrückungen von zwei als vier gezählt werden ...
Matt Fletcher
@aexl: Das war keine Anforderung des OP
Thor
@mattfletcher: Bei der Frage ging es darum, 4 Leerzeichen durch 2 zu ersetzen, sodass ich Ihren Standpunkt nicht verstehe
Thor,
4

Wenn nur führende Leerzeichen konvertiert werden sollen:

sed 'h;s/[^ ].*//;s/    /  /g;G;s/\n *//'

Mit Kommentaren:

sed '
  h; # save a copy of the pattern space (filled with the current line)
     # onto the hold space
  s/[^ ].*//; # remove everything starting with the first non-space
              # from the pattern space. That leaves the leading space
              # characters
  s/    /  /g; # substitute every sequence of 4 spaces with 2.
  G; # append a newline and the hold space (the saved original line) to
     # the pattern space.
  s/\n *//; # remove that newline and the indentation of the original
            # line that follows it'

Schauen Sie sich auch die 'ts'Einstellungen und :retabBefehle von vim an

Stéphane Chazelas
quelle
Gibt es unter Verwendung Ihrer vim-Lösung eine Möglichkeit, mehrere Dateien wie diese mit vim stapelweise zu bearbeiten? Andernfalls denke ich, ich müsste ein Makro erstellen?
Chrisjlee
Beachten Sie, dass 'ts'und :retabkeine Lösungen für die Frage sind, sondern verwandte und dazu beitragen können, Ihr Gesamtziel zu erreichen. Sie können tun vim -- *.c, :set ts=...und dann :argdo retaboder :argdo retab!. Siehe auch die 'sw'Einrückungsfunktionen von Option und vim.
Stéphane Chazelas
2
sed 's/^\( \+\)\1\1\1/\1\1/' file

Es funktioniert, indem die führenden Leerzeichen in vier Instanzen derselben Gruppe aufgeteilt werden (sodass sie alle gleich sind) und dann durch nur zwei Instanzen der Gruppe ersetzt werden.

Mal
quelle
Wie verbessert dies die vorhandenen Lösungen?
Philippos
1
Es behält ungerade Leerzeichen bei, wirkt sich nur auf führende Leerzeichen aus, erfordert kein globales Flag, kann leicht so angepasst werden, dass es eine beliebige Anzahl von Leerzeichen (oder Tabulatoren) auf beiden Seiten des Ersatzes behandelt, und verwendet keine komplexeren sed-Befehle kann für gelegentlichere Benutzer abstoßend sein. Wie bei vielen Dingen ist die Frage, ob es sich um eine Verbesserung handelt, ziemlich subjektiv, aber für mich selbst zu sprechen: Es wäre bedeutend einfacher, dies in einem Skript zu finden, als es bei einigen der anderen aufgeführten Lösungen der Fall ist.
Mal
Interessant. Ich bin froh, dass ich gefragt habe. Normalerweise werden Rückverweise eher als böse denn als globale Flagge betrachtet. Aber Sie könnten das Gleiche leicht mit tragbareren Skripten erreichen (Vermeidung \+). Vielen Dank.
Philippos
1
sed 's/    \{2,4\}\( \{0,1\}[^ ].*\)*/  \1/g' <input

Das sollte nur führende Sequenzen von Räumen zusammenpressen.

mikeserv
quelle