sed converte 4 spazi in 2


14

Come si convertono 4 spazi in 2 spazi con sed? È possibile?

Ho trovato questo ma converte la scheda in spazi:

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

Risposte:


13

Lo script che hai pubblicato converte 4 * n spazi in n tab, solo se tali spazi sono preceduti solo da tab.

Se vuoi sostituire 4 spazi con 2 spazi, ma solo nella rientranza, mentre è possibile farlo con sed, consiglio invece 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

Potresti voler usare indentinvece.


Ho ricevutoNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
eddygeek il

1
@eddygeek Oh, davvero, quello e alcuni altri bug. Ho sostituito il gobbledygook con il vero codice perl.
Gilles 'SO-smetti di essere malvagio' il

5

Il modo semplice non funziona:

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

In caso contrario, pubblica alcuni input dove non riesce.


1
Questo non è limitato all'inizio della riga. Se lo ancorate lì, non funzionerà per più corrispondenze. Quindi siamo su unix.stackexchange.com/a/375200/259620 di seguito.
geek-merlin,

Questo non funziona se hai una combinazione di 2 spazi e 4 spazi, perché due rientri di due verranno contati come quattro ...
Matt Fletcher,

@aexl: Non era un requisito richiesto dall'OP
Thor,

@mattfletcher: la domanda riguardava la sostituzione di 4 spazi con 2, quindi non riesco a vedere il tuo punto
Thor,

4

Se devono essere convertiti solo gli spazi iniziali:

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

Con commenti:

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'

Guarda anche le 'ts'impostazioni e il :retabcomando di vim


Usando la tua soluzione vim, c'è un modo per modificare in batch diversi file come quello con vim? Altrimenti immagino che dovrei creare una macro?
chrisjlee,

Si noti che 'ts'e :retabnon sono soluzioni alla questione, ma sono legate e possono contribuire ad affrontare il vostro obiettivo generale. Puoi fare vim -- *.c, :set ts=...e poi :argdo retabo :argdo retab!. Vedi anche l' 'sw'opzione e le capacità di rientro di vim.
Stéphane Chazelas,

2
sed 's/^\( \+\)\1\1\1/\1\1/' file

Funziona dividendo gli spazi iniziali in quattro istanze dello stesso gruppo (quindi sono tutti uguali) e quindi sostituendoli con solo due istanze del gruppo.


In che modo questo migliora le soluzioni esistenti?
Philippos,

1
Conserva gli spazi dispari, interessa solo gli spazi bianchi iniziali, non richiede la bandiera globale, può essere facilmente ottimizzato per gestire qualsiasi numero di spazi (o schede) su entrambi i lati della sostituzione e non utilizza comandi sed più complessi che può essere scoraggiante per gli utenti più occasionali. Come per molte cose, se si tratta di un miglioramento è piuttosto soggettivo, ma parlando da solo: trovarlo in una sceneggiatura sarebbe significativamente più facile da individuare rapidamente rispetto ad alcune delle altre soluzioni elencate.
Mal

Interessante. Sono contento di averlo chiesto. Di solito i riferimenti arretrati sono considerati malvagi piuttosto che la bandiera globale. Ma potresti facilmente ottenere la stessa cosa con uno script più portatile (evitando \+). Grazie.
Philippos,

1
sed 's/    \{2,4\}\( \{0,1\}[^ ].*\)*/  \1/g' <input

Ciò dovrebbe solo spremere sequenze di spazi principali.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.