sed mengkonversi 4 spasi menjadi 2

14

Bagaimana seseorang mengkonversi 4 spasi menjadi 2 spasi dengan sed? Apa itu mungkin?

Saya menemukan ini tetapi itu mengonversi tab ke spasi:

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

chrisjlee
sumber

Jawaban:

13

Skrip yang Anda posting mengonversi 4 * n spasi menjadi n tab, hanya jika spasi tersebut didahului hanya dengan tab.

Jika Anda ingin mengganti 4 spasi dengan 2 spasi, tetapi hanya dalam lekukan, sementara itu mungkin dilakukan dengan sed, saya sarankan Perl sebagai gantinya.

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

Sed:

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

Anda mungkin ingin menggunakannya indent.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya mendapatNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
eddygeek
1
@eddygeek Oh, memang, itu dan beberapa bug lainnya. Saya mengganti gobbledygook dengan kode perl yang sebenarnya.
Gilles 'SO- stop being evil'
5

Tidak dengan cara langsung:

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

Jika tidak, posisikan beberapa input jika gagal.

Thor
sumber
1
Ini tidak dibatasi pada awal baris. Jika Anda menambatkannya di sana, itu tidak akan berfungsi untuk beberapa pertandingan. Jadi kami di unix.stackexchange.com/a/375200/259620 di bawah ini.
geek-merlin
Ini tidak berfungsi jika Anda memiliki kombinasi 2 spasi dan 4 spasi, karena dua lekukan dua akan dihitung sebagai empat ...
Matt Fletcher
@ aexl: Itu bukan persyaratan OP
Thor
@mattfletcher: pertanyaannya adalah tentang mengganti 4 spasi dengan 2, jadi saya gagal melihat maksud Anda
Thor
4

Jika hanya spasi yang akan dikonversi:

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

Dengan komentar:

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'

Juga lihat 'ts'pengaturan dan :retabperintah vim

Stéphane Chazelas
sumber
Menggunakan solusi vim Anda, apakah ada cara untuk mengedit beberapa file seperti itu dengan vim? Kalau tidak, saya kira saya harus membuat makro?
chrisjlee
Perhatikan bahwa 'ts'dan :retabbukan solusi untuk pertanyaan, tetapi terkait dan dapat membantu mengatasi sasaran keseluruhan Anda. Anda bisa melakukannya vim -- *.c, :set ts=...lalu :argdo retabatau kemudian :argdo retab!. Lihat juga 'sw'opsi dan kemampuan indentasi vim sendiri.
Stéphane Chazelas
2
sed 's/^\( \+\)\1\1\1/\1\1/' file

Ini bekerja dengan membagi spasi memimpin menjadi empat instance dari grup yang sama (jadi mereka semua sama) dan kemudian menggantinya dengan hanya dua instance dari grup.

Mal
sumber
Bagaimana cara meningkatkan solusi yang ada?
Philippos
1
Ini mempertahankan ruang aneh, hanya mempengaruhi spasi putih terkemuka, tidak memerlukan bendera global, dapat dengan mudah di-tweak untuk menangani sejumlah ruang (atau tab) di kedua sisi penggantian dan tidak menggunakan perintah sed yang lebih kompleks yang bisa membuat off-menempatkan untuk lebih banyak pengguna biasa. Seperti banyak hal, apakah itu perbaikan cukup subyektif, tetapi berbicara sendiri: menemukan ini dalam skrip akan jauh lebih mudah dengan cepat grok daripada beberapa solusi lain yang tercantum.
Mal
Menarik. Senang saya memang bertanya. Biasanya referensi kembali dianggap jahat daripada bendera global. Tetapi Anda dapat dengan mudah mencapai hal yang sama dengan lebih banyak skrip portabel (menghindari \+). Terima kasih.
Philippos
1
sed 's/    \{2,4\}\( \{0,1\}[^ ].*\)*/  \1/g' <input

Itu seharusnya hanya menekan urutan ruang terkemuka.

mikeserv
sumber