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.