Apa cara paling sederhana untuk menghapus spasi spasi dari semua baris dalam file?

139

Ini cukup umum ketika pemrograman atau membuka file teks untuk menemukan file dengan spasi spasi di akhir baris. vim memiliki cara untuk menunjukkan ini dengan mengatur trailopsi pada listcharsopsi lalu menghidupkan list.

Namun, apa cara termudah untuk menghilangkan spasi spasi global di seluruh file (idealnya tanpa plugin)?

Andrew Ferrier
sumber
Berikut ini adalah entri dokumen pada topik.
Filipp W.
Jika Anda telah menginstal vim-faq , Anda bisa mendapatkan jawaban offline di sana: :h vim-faqdan cari /trailing. Tag yang sulit diingat adalah :h faq-12.1.
Hotschke

Jawaban:

72

Gunakan pengikat kunci untuk menghapus semua spasi spasi

Karena beberapa halaman yang saya edit benar-benar membutuhkan trailing spasi (mis. Markdown) dan yang lain tidak, saya membuat keybinding F5sehingga sepele untuk dilakukan tanpa otomatis. Untuk melakukannya, tambahkan kode di bawah ini (dari vim.wikia) atau beberapa variasi untuk Anda .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>melakukan pemetaan non-rekursif ke tombol F5dalam mode normal
  • :let _s=@/menyimpan istilah pencarian terakhir (dari makro @/) dalam variabel_s
  • <Bar>Berfungsi sebagai simbol pipa |untuk memisahkan perintah, namun |akan mengakhiri perintah dalam konteks ini, jadi <Bar>harus digunakan sebagai gantinya.
  • :%s/\s\+$//emencari trailing whitespace dan menghapusnya di mana-mana di buffer (lihat jawaban CarpetSmoker untuk rincian terperinci dari ungkapan ini)
  • let @/=_smengembalikan istilah pencarian terakhir Anda ke makro @/, sehingga akan tersedia saat Anda menekan berikutnya n.
  • <CR> mengakhiri pemetaan

... atau lebih selektif

Jika Anda memiliki case di mana Anda tidak ingin menghapus semua spasi spasi, Anda bisa menggunakan pola untuk lebih selektif. Sebagai contoh, kode berikut ini menunjukkan bagaimana saya menghapus trailing spasi hanya jika itu datang setelah tanda titik koma (di sini ini terkait dengan F8).

nnoremap <F8> :let _s=@/<Bar>:%s/;\s\+$/;/e<Bar>:let @/=_s<Bar><CR>

Ini berguna jika, seperti saya, Anda memiliki beberapa file dengan heredocs mirip-markdown diselingi di antara pernyataan pemrograman yang diakhiri dengan titik koma.

Christopher Bottoms
sumber
6
Cobalah :keeppatternsuntuk mencegah penggantian @/. Dan lihat juga :keepjumps.
Bohr
@ Bohr Versi vim apa yang Anda gunakan? Saya mencoba :help keeppatterndan tidak mendapatkan apa pun.
Christopher Bottoms
@ChristopherBottoms Setidaknya versi 7.4.155 .
Bohr
@ Bob. Terima kasih! Ayo cari tahu saya masih menggunakan 7.4.0. Saya menginstal versi terbaru dan tersedia.
Christopher Bottoms
2
Anda bisa mendapatkan efek yang sama dengan membungkus perintah ini dalam suatu fungsi, sejak saat itu istilah pencarian terakhir secara otomatis dipulihkan :-) Dengan cara ini Anda tidak perlu bercampur dengan :nohlbaik, jika jika Anda sedang menyoroti sesuatu, itu akan terus menyoroti itu (lihat jawaban saya yang diperbarui).
Martin Tournoij
175

Cara "paling sederhana" adalah dengan hanya menggunakan :substitute:

:%s/\s\+$//e
  • :%suntuk menjalankan :substituterentang %, yang merupakan seluruh buffer.
  • \s t cocok dengan semua karakter spasi putih.
  • \+ untuk mengulanginya 1 kali atau lebih.
  • $ untuk berlabuh di ujung garis.
  • The ebendera untuk tidak memberikan kesalahan jika tidak ada pertandingan (yaitu file sudah tanpa trailing spasi).

Namun, ini mungkin bukan cara "terbaik" karena menyebabkan dua efek samping:

  1. itu memindahkan kursor ke pertandingan terakhir;
  2. itu menambah perintah ke histori dan search history;
  3. me-reset istilah pencarian terakhir.

Anda dapat memperbaiki kedua item dengan mengubahnya menjadi fungsi:

fun! TrimWhitespace()
    let l:save = winsaveview()
    keeppatterns %s/\s\+$//e
    call winrestview(l:save)
endfun

Dan kemudian gunakan seperti:

:call TrimWhitespace()
  1. Ini winsaveview()akan menyimpan "tampilan" saat ini, yang mencakup posisi kursor, lipatan, lompatan, dll. Pada winrestview()akhirnya akan mengembalikan ini dari variabel yang disimpan.
  2. The :keeppatternsmencegah \s\+$pola dari yang ditambahkan ke riwayat pencarian.
  3. Istilah pencarian yang terakhir digunakan secara otomatis dikembalikan setelah meninggalkan fungsi, jadi kami tidak perlu melakukan hal lain untuk ini.

Karena ini agak menjengkelkan untuk mengetik :callsepanjang waktu, Anda dapat mendefinisikan perintah:

command! TrimWhitespace call TrimWhitespace()

Yang dapat digunakan tanpa :call:

:TrimWitespace

Dan tentu saja Anda dapat mengikatnya ke kunci:

:noremap <Leader>w :call TrimWhitespace()<CR>

Beberapa orang suka melakukan ini secara otomatis sebelum mereka menulis file ke disk, seperti:

autocmd BufWritePre * :call TrimWhitespace()

Saya tidak suka, karena beberapa format memerlukan trailing spasi (seperti penurunan harga), dan pada beberapa kesempatan lain Anda bahkan ingin trailing spasi dalam kode Anda (seperti memformat email, dan menggunakan --<Space>penanda untuk menunjukkan awal tanda tangan ).


Modus plug Shameless: beberapa waktu lalu saya menulis skrip Python kecil untuk membersihkan spasi putih untuk seluruh proyek sekaligus.

Martin Tournoij
sumber
1
Jika Anda tidak ingin membuat fungsi untuk pindah ke posisi sebelumnya, Anda cukup menekan ​`​dua kali setelah penggantian selesai. Ini membuka kemungkinan untuk membuat oneliner seperti ini:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel
1
@ NeaţuOvidiuGabriel, tentu saja maka backtick ganda tidak akan berfungsi sama setelah oneliner dieksekusi. ;)
Wildcard
Serupa: stackoverflow.com/a/1618401 . Tapi saya lebih suka kode Martin.
john cj
11

Untuk menghapus semua spasi spasi tambahan (di akhir setiap baris), Anda dapat menggunakan perintah:

:%s/ \+$//

Untuk memasukkan tab, gunakan \sbukan ruang.


Dari baris perintah:

$ ex +'%s/\s\+$//e' -cwq file.c

Semua file di direktori saat ini (digunakan secara rekursif **/*.*):

$ ex +'bufdo!%s/\s\+$//e' -cxa *.*

Cara python:

:py import vim
:pydo vim.current.buffer[linenr - 1] = vim.current.buffer[linenr - 1].strip()

atau:

:py import vim
:py for i, l in enumerate(vim.current.buffer): vim.current.buffer[i] = l.rstrip()

Gunakan lstrip()untuk strip kiri (trailing), rstrip()untuk strip kanan (depan) atau strip()untuk menghapus dari kedua ujungnya.


Berikut adalah fungsi yang berguna yang menghilangkan ruang putih berlebihan dari ujung garis yang dapat Anda tambahkan ke .vimrc:

" Removes superfluous white space from the end of a line
function! RemoveWhiteSpace()
   :%s/\s*$//g
    :'^
    "`.
endfunction

Ada juga plugin DeleteTrailingWhitespace untuk itu.


Menyoroti ruang putih

Untuk memeriksa ulang apakah semua spasi tambahan hilang, gunakan:

  1. Ketik / $untuk menemukannya. Jika ada beberapa, vim akan menyorotinya untuk Anda.

  2. Gunakan warna untuk menyorotnya:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Gunakan karakter yang terlihat ( sumber ):

    :set encoding=utf-8
    :set listchars=trail:·
    :set list
    

Lihat juga: Sorot ruang yang tidak diinginkan

Untuk menyorot jejak spasi kosong secara default, Anda dapat mengonfigurasi .vimrcsebagai berikut:

highlight ws ctermbg=red guibg=red
match ws /\s\+$/
autocmd BufWinEnter * match ws / \+$/

Menghapus spasi putih secara default

Jika Anda ingin memastikan bahwa semua spasi kosong dalam file dihapus secara otomatis saat save, Anda dapat menambahkan perintah berikut ke dalam .vimrc:

autocmd BufWritePre *.c,*.php :%s/ \+$//ge

yang tidak direkomendasikan, karena akan menghapus trailing spasi dari setiap file yang disimpan pengguna (bahkan di mana spasi putih dapat diinginkan).


Lihat juga:

kenorb
sumber
5

Mengulas sedikit atas jawaban Christopher Bottoms : Jonathan Palardy menulis artikel yang bagus tentang ini . Di dalamnya, ia menulis sebuah fungsi,, Preserve(command)yang menjaga status editor (terutama posisi kursor dan pola pencarian terakhir) saat menjalankan perintah arbitrer:

function! Preserve(command)
  " Preparation: save window state
  let l:saved_winview = winsaveview()
  " Run the command:
  execute a:command
  " Clean up: restore previous window position
  call winrestview(l:saved_winview)
endfunction

Ini memiliki keuntungan menjadi multiguna, misalnya Anda dapat menggunakannya untuk mengganti semua spasi spasi (seperti yang dilakukan Jonathan) dengan memetakan ini ke:

nnoremap <F5> :call Preserve("%s/\\s\\+$//e")<CR>

Anda juga dapat menggunakannya untuk pemetaan mode visual untuk hanya menghapus spasi tambahan pada garis yang dipilih secara visual:

xnoremap <F5> :call Preserve("'<,'>s/\\s\\+$//e")<CR>

Dan Anda dapat menggunakannya untuk panggilan lain, seperti memformat seluruh dokumen menggunakan =sambil mempertahankan tempat Anda (baik gunakan kunci yang berbeda kali ini agar tidak bertentangan):

nnoremap <F6> :call Preserve("normal gg=G")<CR>

Semua dan semua, saya telah menemukan Preserve(command)fungsi untuk menjadi alat yang bagus untuk dimiliki.

Alex
sumber
2
Istilah pencarian yang terakhir digunakan harus secara otomatis dipertahankan ketika Anda meninggalkan suatu fungsi; jadi mucking dengan @/seharusnya tidak diperlukan (dalam hal ini, bagaimanapun).
Martin Tournoij
3
winsaveview()dan winrestview()jauh lebih unggul.
dash-tom-bang
Benar sekali! Diperbarui berdasarkan umpan balik Anda.
Alex
0

Versi lain dari Fungsi StripTrailingSpaces:

if !exists('*StripTrailingWhitespace')
    function! StripTrailingWhitespace() range
        if !&binary && &filetype != 'diff'
            call Preserve(":" . a:firstline . "," . a:lastline . "s/\\s\\+$//e")
        endif
    endfunction
endif

SEBENARNYA ADA BUG DALAM FUNGSI INI (yang ini): kepemilikannya tidak disimpan karena opsi "range". itu dihapus berfungsi dengan sangat baik, namun saya membagikan kode untuk menerima bantuan.

Seperti yang Anda lihat, ia juga menggunakan fungsi Preserve yang terlihat di atas, tetapi dengan cara yang sedikit berbeda.

Perbedaannya di sini adalah bahwa saya dapat memilih rentang baris atau paragraf dengan vipdan kemudian rentang tersebut :'<,'>akan secara otomatis muncul pada command prompt.

Ide itu datang dari pos Bez Hermoso .

SergioAraujo
sumber