sed converte 4 espaços em 2


14

Como converter 4 espaços em 2 espaços com sed? É possível?

Achei isso, mas ele converte tabulação em espaços:

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

Respostas:


13

O script que você postou converte 4 * n espaços em n guias, somente se esses espaços forem precedidos apenas por guias.

Se você deseja substituir 4 espaços por 2 espaços, mas apenas em recuo, embora seja possível fazê-lo com sed, eu recomendo o Perl.

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

Em sed:

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

Você pode usar em seu indentlugar.


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

1
@eddygeek Oh, de fato, isso e alguns outros erros. Substituí o gobbledygook pelo código perl real.
— Gilles 'SO- stop be evil'

5

O caminho direto não funciona:

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

Caso contrário, publique alguma entrada onde ela falhar.


1
Isso não é restrito ao início da linha. Se você o ancorar lá, ele não funcionará para várias correspondências. Portanto, estamos em unix.stackexchange.com/a/375200/259620 abaixo.
— geek-merlin

Isso não funciona se você tiver uma combinação de 2 lugares e 4 espaços, porque dois recortes de dois será contado como quatro ...
— Matt Fletcher

@ aexl: Isso não era um requisito pelo OP
— Thor

@mattfletcher: a pergunta era sobre a substituição de 4 espaços com 2, então eu não vejo o seu ponto
— Thor

4

Se apenas espaços iniciais forem convertidos:

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

Com comentários:

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'

Veja também a 'ts'configuração e o :retabcomando do vim


Usando sua solução vim, existe uma maneira de editar em lote vários arquivos como esse com o vim? Caso contrário, eu acho que eu teria que criar uma macro?
— Chrisjlee # 10/12

Observe que 'ts'e :retabnão são soluções para a pergunta, mas estão relacionadas e podem ajudar a atingir seu objetivo geral. Você pode fazer vim -- *.c, :set ts=...e então :argdo retabou :argdo retab!. Consulte também a 'sw'opção e os recursos de recuo do vim.
— Stéphane Chazelas

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

Ele funciona dividindo os espaços iniciais em quatro instâncias do mesmo grupo (para que todos sejam iguais) e depois substituindo-os por apenas duas instâncias do grupo.


Como isso melhora as soluções existentes?
— Philippos

1
Ele preserva espaços ímpares, afeta apenas os espaços em branco à esquerda, não requer o sinalizador global, pode ser facilmente ajustado para lidar com qualquer número de espaços (ou guias) nos dois lados da substituição e não utiliza comandos sed mais complexos que pode ser desanimador para usuários mais casuais. Como em muitas coisas, se é uma melhoria bastante subjetiva, mas falando por mim: encontrar isso em um script seria significativamente mais fácil de entender rapidamente do que algumas das outras soluções listadas.
— Mal

Interessante. Ainda bem que perguntei. Normalmente, as referências anteriores são consideradas más, e não a bandeira global. Mas você poderia facilmente conseguir a mesma coisa com scripts mais portáteis (evitando \+). Obrigado.
— Philippos

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

Isso deve apenas espremer as principais seqüências de espaços.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.