Bagaimana saya bisa mengonversi spasi menjadi tab di Vim atau Linux?


192

Saya telah melihat beberapa pertanyaan tentang Stack Overflow untuk bagaimana mengkonversi spasi menjadi tab tanpa menemukan apa yang saya butuhkan. Tampaknya ada lebih banyak pertanyaan tentang cara mengubah tab menjadi spasi, tapi saya mencoba melakukan yang sebaliknya.

Dalam VimSaya sudah mencoba :retabdan :retab!tidak berhasil, tapi saya percaya itu sebenarnya untuk pergi dari tab ke spasi.

Saya mencoba keduanya expanddan unexpandpada command prompt tanpa hasil.

Ini file yang dimaksud:

http://gdata-python-client.googlecode.com/hg-history/a9ed9edefd61a0ba0e18c43e448472051821003a/samples/docs/docs_v3_example.py

Bagaimana saya bisa mengonversi spasi utama ke tab menggunakan salah satu Vimatau shell?


Dalam komentar @ Matt yang sekarang dihapus, contoh pertama ( sed "s/ +/`echo -e '\t'`/g" < input.py > output.py) muncul untuk mengonversi semua spasi, bukan hanya memimpin spasi. Dalam contoh kedua ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py) itu hanya mengganti spasi pertama pada setiap baris dengan tab dan meninggalkan sisanya.
cwd


Saya tidak menemukan jawaban untuk semua / banyak file , jadi saya sudah menulis sendiri: stackoverflow.com/a/44581474/1115187 . Dengan find, awkdan blackjack (terlalu lama untuk meninggalkannya dalam komentar, meskipun)
maxkoryukov

Jawaban:


316

Menggunakan Vim untuk memperluas semua ruang utama (lebih luas dari 'tabstop'), Anda benar untuk menggunakan retabtetapi pastikan terlebih dahulu 'expandtab'diatur ulang ( :verbose set ts? et?adalah teman Anda). retabDibutuhkan rentang , jadi saya biasanya menentukan %berarti "seluruh file".

:set tabstop=2      " To match the sample file
:set noexpandtab    " Use tabs, not spaces
:%retab!            " Retabulate the whole file

Sebelum melakukan hal seperti ini (terutama dengan file Python!), Saya biasanya mengatur 'list', sehingga saya bisa melihat spasi dan berubah.

Saya memiliki pemetaan berikut dalam saya.vimrc untuk ini:

nnoremap    <F2> :<C-U>setlocal lcs=tab:>-,trail:-,eol:$ list! list? <CR>

2
inilah cara saya mendapatkannya untuk bekerja, tidak yakin apa yang diperlukan dan apa yang tidak, dan btw saya tidak tahu apa yang "%" sebelum reatab melakukan: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
CWD

2
Saya telah memperbarui jawaban saya untuk memasukkan penjelasan mengapa saya menggunakan %. Pemetaan F2 persis seperti yang diketiknya .
Johnsyweb

7
Untuk file tertentu, saya hanya akan melakukan::set noet ts=2 |%retab!
Johnsyweb

1
@Johnsyweb agar adil, saya salah: :%retab!masih berfungsi. Saya bingung dengan ==, dll yang tidak menghormati pengaturan preserveindent.
Unk

1
Untuk mengonversi file coffeescript dari spasi ke tab, saya mengikuti jawaban @ Johnsyweb (termasuk penambahan ke file .vimrc) tetapi sebaliknya dengan:set tabstop=4
Mikeumus

38

1 - Jika Anda memiliki spasi dan ingin tab.

Pertama, Anda perlu memutuskan berapa banyak ruang yang akan memiliki satu tab. Yang mengatakan, misalkan Anda memiliki garis dengan memimpin 4 spasi, atau 8 ... Dari yang Anda sadari Anda mungkin ingin tab menjadi 4 spasi. Sekarang dengan info itu, Anda lakukan:

:set ts=4
:set noet
:%retab!

Ada masalah di sini! Urutan perintah ini akan mencari semua teks Anda, tidak hanya spasi di awal baris. Itu berarti string seperti: "Hey,␣this␣␣␣␣is␣4␣spaces"akan menjadi "Hey,␣this⇥is␣4␣spaces", tetapi tidak! itu tab !.

Untuk menyelesaikan masalah kecil ini saya merekomendasikan search, bukannya retab.

:%s/^\(^I*\)␣␣␣␣/\1^I/g

Pencarian ini akan mencari di seluruh file untuk setiap baris yang dimulai dengan jumlah tab apa pun, diikuti oleh 4 spasi, dan menggantinya dengan jumlah tab apa pun yang ditemukan ditambah satu.

Sayangnya, ini tidak akan berjalan sekaligus!

Pada awalnya, file akan memiliki garis yang dimulai dengan spasi. Pencarian kemudian akan mengkonversi hanya 4 spasi pertama ke tab, dan biarkan yang berikut ...

Anda harus mengulangi perintahnya. Berapa kali? Sampai Anda mendapatkan pattern not found. Saya belum bisa memikirkan cara untuk mengotomatiskan prosesnya. Tetapi jika Anda melakukannya:

`10@:`

Anda mungkin sudah selesai. Perintah ini mengulangi pencarian / penggantian terakhir untuk 10 kali. Sepertinya program Anda tidak akan memiliki banyak indentasi. Jika sudah, ulangi lagi @@.

Sekarang, cukup lengkapi jawabannya. Saya tahu Anda meminta yang sebaliknya, tetapi Anda tidak pernah tahu kapan Anda harus membatalkan sesuatu.

2 - Anda memiliki tab dan ingin spasi.

Pertama, tentukan berapa banyak ruang yang Anda ingin tab Anda konversi. Katakanlah Anda ingin setiap tab menjadi 2 spasi. Anda kemudian melakukan:

:set ts=2
:set et
:%retab!

Ini akan memiliki masalah yang sama dengan string. Tetapi karena gaya pemrogramannya yang lebih baik untuk tidak menggunakan tab keras di dalam string, Anda sebenarnya melakukan hal yang baik di sini. Jika Anda benar-benar membutuhkan tab di dalam string, gunakan \t.


Sepertinya kondisi balapan yang sangat langka. Pokoknya, buat fungsi yang menerima pemilihan rentang visual dan ulangi fungsi pencarian sampai tidak ada yang cocok, saya kira itu akan menjadi jawaban yang lebih pintar dan berguna.
albfan

Ya, atau itu. Jika Anda menginginkan solusi yang lebih pasti, Anda dapat menggunakan suatu fungsi. Lagi pula, itu selalu baik untuk mengetahui bagaimana melakukannya di ex command, karena ini akan menjadi apa yang ada di dalam fungsi. Dan tidak, itu tidak jarang. Anda hanya perlu memiliki string dengan spasi agar berantakan. Tidak jarang sama sekali. Saya sudah di sana. Terima kasih sudah berkomentar.
Dr Beco

Tolong jelaskan mengapa / g tidak cukup untuk mengonversi semua grup dari 4 di setiap baris berturut-turut menjadi tab, alih-alih harus menjalankan pencarian beberapa kali.
Bjartur Thorlacius

Hai @BjarturThorlacius, masalahnya adalah jika Anda menghapus ^simbol, untuk memulai pencarian dari awal baris, Anda berisiko mengubah ruang di dalam string. Dengan ^jaminan Anda hanya mengubah spasi dan tab sejak awal baris, karenanya, lekukan. Selain itu, jika Anda yakin tidak masalah untuk melakukan semuanya sekaligus, hapus ^dan jalankan hanya sekali dengan::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr Beco

15
:%s/\(^\s*\)\@<=    /\t/g

Penerjemahan: Cari setiap instance dari 4 spasi berurutan (setelah karakter =), tetapi hanya jika seluruh baris hingga titik tersebut adalah spasi putih (ini menggunakan pernyataan selebar pandang lebar-nol, \@<=). Ganti setiap instance yang ditemukan dengan karakter tab.


1
Satu-satunya solusi yang bekerja untuk memperluas 1 ruang menjadi 1 tab , tetapi berhati-hatilah terhadap unicode dalam jawabannya, saya hanya menggunakan :%s/\(^\s*\)\@<= /\t/g- masukkan jumlah spasi yang sesuai (untuk mengonversi 4 spasi menjadi 1 tab, masukkan 4 spasi) tepat setelah<=
Orwellophile

5

Mengubah semua spasi menjadi tab:% s / \ s / \ t / g


Inilah tepatnya yang saya butuhkan. Terima kasih. Satu-satunya perubahan yang harus saya lakukan adalah mengganti setiap 4 spasi dengan tab alih-alih melakukan setiap ruang tunggal.
Orang Anonim

3

Linux: dengan unexpand(dan expand)

Berikut adalah solusi yang sangat baik: https://stackoverflow.com/a/11094620/1115187 , sebagian besar karena menggunakan * nix-utilities:

  1. buka - spasi -> tab
  2. rentangkan - tab -> spasi

Linux: skrip khusus

Jawaban asli saya

Cuplikan Bash untuk mengganti lekukan 4 spasi (ada dua {4}skrip) dengan tab di semua .pyfile di ./appfolder (secara rekursif):

find ./app -iname '*.py' -type f \
    -exec awk -i inplace \
    '{ match($0, /^(( {4})*)(.*?)$/, arr); gsub(/ {4}/, "\t", arr[1]) }; { print arr[1] arr[3] }' {} \; 

Itu tidak memodifikasi 4 spasi di tengah atau di akhir.

Diuji di bawah Ubuntu 16.0x dan Linux Mint 18


0

Dalam kasus saya, saya memiliki beberapa spasi (bidang dipisahkan oleh satu ruang atau lebih) yang ingin saya ganti dengan tab. Berikut ini melakukannya:

:% s/\s\+/\t/g

0

Jika Anda telah GNU coreutils diinstal, mempertimbangkan %!unexpand --first-onlyatau tab 4-ruang, mempertimbangkan %!unexpand -t 4 --first-only( --first-onlyhadir hanya dalam kasus Anda tidak sengaja memohon unexpanddengan --all).

Perhatikan bahwa ini hanya akan menggantikan ruang sebelum tab yang ditentukan berhenti, bukan ruang yang mengikutinya; Anda tidak akan melihat perbedaan visual dalam vim kecuali Anda menampilkan tab secara lebih harfiah; misalnya, saya ~/.vimrcmengandung set list listchars=tab:▸┈(saya menduga ini adalah mengapa Anda berpikir unexpandtidak bekerja).


0

Untuk menggunakan Vim untuk me-retab satu set file (mis. Semua file * .ts dalam hierarki direktori) dari katakanlah 2 spasi hingga 4 spasi Anda bisa mencoba ini dari baris perintah:

find . -name '*.ts' -print0 | xargs -0 -n1 vim -e '+set ts=2 noet | retab! | set ts=4 et | retab | wq'

Apa yang dilakukan adalah menggunakan finduntuk meneruskan semua file yang cocok ke xargs(opsi-print0 pada menemukan bekerja dengan opsi -0 ke xargs untuk menangani file dengan spasi dalam nama).

xargs menjalankan vim dalam mode ex ( -e) pada setiap file yang mengeksekusi perintah ex yang diberikan yang sebenarnya adalah beberapa perintah, untuk mengubah spasi terdepan yang ada menjadi tab, mengatur ulang tab berhenti dan mengubah tab kembali ke spasi dan akhirnya menyimpan dan keluar.

Berjalan dalam mode ex mencegah hal ini: Vim: Warning: Input is not from a terminaluntuk setiap file.


-1

Skrip Python Sederhana:

import os

SOURCE_ROOT = "ROOT DIRECTORY - WILL CONVERT ALL UNDERNEATH"

for root, dirs, files in os.walk(SOURCE_ROOT):
    for f in files:
        fpath = os.path.join(root,f)
        assert os.path.exists(fpath)
        data = open(fpath, "r").read()
        data = data.replace("    ", "\t")
        outfile = open(fpath, "w")
        outfile.write(data)
        outfile.close()

Satu masalah besar: cuplikan ini menggantikan semua 4 ruang, tidak hanya lekukan (di awal baris)
maxkoryukov

dan yang kedua: file-filter tidak diimplementasikan
maxkoryukov
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.