sed przekształca 4 spacje na 2

14

Jak przekonwertować 4 spacje na 2 spacje sed? Czy to możliwe?

Znalazłem to, ale konwertuje tabulatory na spacje:

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

chrisjlee
źródło

Odpowiedzi:

13

Wysłany skrypt konwertuje 4 * n spacji na n tabulatorów, tylko jeśli te spacje są poprzedzone tylko tabulatorami.

Jeśli chcesz zastąpić 4 spacje 2 spacjami, ale tylko z wcięciem, chociaż można to zrobić za pomocą sed, polecam zamiast tego Perla.

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

W sed:

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

Możesz indentzamiast tego użyć .

Gilles „SO- przestań być zły”
źródło
DostałemNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
eddygeek
1
@eddygeek Och, rzeczywiście, to i kilka innych błędów. Zastąpiłem gobbledygook rzeczywistym kodem perla.
Gilles 'SO - przestań być zły'
5

Czy prosty sposób nie działa:

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

Jeśli nie, opublikuj dane wejściowe tam, gdzie się nie powiedzie.

Thor
źródło
1
Nie jest to ograniczone do początku linii. Jeśli go zakotwiczycie, nie będzie działać dla wielu dopasowań. Jesteśmy na unix.stackexchange.com/a/375200/259620 poniżej.
geek-merlin
To nie działa, jeśli masz kombinację 2 spacji i 4 spacji, ponieważ dwa wcięcia po dwa będą liczone jako cztery ...
Matt Fletcher
@ aexl: Nie był to wymóg OP
Thor
@mattfletcher: pytanie dotyczyło zamiany 4 spacji na 2, więc nie rozumiem twojego sensu
Thor
4

Jeśli mają być konwertowane tylko spacje wiodące:

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

Z komentarzami:

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'

Zobacz także 'ts'ustawienia i :retabpolecenia vima

Stéphane Chazelas
źródło
Czy korzystając z rozwiązania vim istnieje sposób na grupową edycję kilku takich plików za pomocą vima? W przeciwnym razie zgaduję, że musiałbym utworzyć makro?
chrisjlee,
Pamiętaj, że 'ts'i :retabnie są to rozwiązania pytania, ale są powiązane i mogą pomóc w osiągnięciu ogólnego celu. Możesz zrobić vim -- *.c, :set ts=...a następnie :argdo retablub :argdo retab!. Zobacz także 'sw'opcję i własne możliwości wcięcia vima.
Stéphane Chazelas,
2
sed 's/^\( \+\)\1\1\1/\1\1/' file

Działa, dzieląc wiodące spacje na cztery wystąpienia tej samej grupy (więc wszystkie są równe), a następnie zastępując je tylko dwoma wystąpieniami grupy.

Mal
źródło
Jak to poprawia istniejące rozwiązania?
Philippos
1
Zachowuje nieparzyste spacje, wpływa tylko na wiodące białe znaki, nie wymaga flagi globalnej, można go łatwo dostosować, aby obsługiwać dowolną liczbę spacji (lub tabulatorów) po obu stronach zastępowania i nie używa bardziej złożonych poleceń sed, które może zniechęcać bardziej zwykłych użytkowników. Podobnie jak w przypadku wielu rzeczy, to, czy jest to poprawa, jest dość subiektywne, ale mówiąc sam za siebie: znalezienie tego w skrypcie byłoby znacznie łatwiejsze do szybkiego sprawdzenia, niż niektóre inne wymienione rozwiązania.
Mal
Ciekawy. Cieszę się, że zapytałem. Zwykle wsteczne odniesienia są uważane za złe, a nie za globalną flagę. Ale możesz łatwo osiągnąć to samo dzięki bardziej przenośnemu skryptowi (unikając \+). Dziękuję Ci.
Philippos
1
sed 's/    \{2,4\}\( \{0,1\}[^ ].*\)*/  \1/g' <input

To powinno tylko ścisnąć wiodące sekwencje przestrzeni.

mikeserv
źródło