Qual è il modo più semplice per eliminare gli spazi bianchi finali da tutte le linee in un file?


139

È abbastanza comune quando si programma o si aprono file di testo per incontrare file con spazi vuoti finali alla fine di una riga. vim ha un modo per mostrarlo impostando l' trailopzione listcharsnell'opzione e quindi accendendo list.

Tuttavia, qual è il modo più semplice per eliminare lo spazio bianco finale su tutto il file (idealmente senza un plugin)?



Ecco una voce doc sull'argomento.
Filipp W.

Se hai installato vim-faq , puoi ottenere una risposta offline lì: :h vim-faqe cerca /trailing. Il tag difficile da memorizzare è :h faq-12.1.
Hotschke,

Risposte:


72

Utilizzare una combinazione di tasti per eliminare tutti gli spazi bianchi finali

Dal momento che alcune pagine che modifico in realtà hanno bisogno di spazi bianchi finali (ad esempio markdown) e altre no, ho impostato un keybinding in F5modo che sia banale fare senza essere automatico. Per fare ciò, aggiungi il codice seguente (da vim.wikia) o una sua variante al tuo .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>esegue una mappatura non ricorsiva sulla chiave F5in modalità normale
  • :let _s=@/memorizza l'ultimo termine di ricerca (dalla macro @/) nella variabile_s
  • <Bar>Funziona come un simbolo di pipe |per separare i comandi, tuttavia |terminerebbe un comando in questo contesto, quindi <Bar>deve essere utilizzato al suo posto.
  • :%s/\s\+$//ecerca spazi vuoti finali e lo elimina ovunque nel buffer (vedere la risposta di CarpetSmoker per una suddivisione dettagliata di questa espressione)
  • let @/=_sripristina l'ultimo termine di ricerca nella macro @/, in modo che sia disponibile la prossima volta che premi n.
  • <CR> termina la mappatura

... o sii più selettivo

Se hai casi in cui non vuoi rimuovere tutto lo spazio bianco finale, puoi usare un modello per essere più selettivo. Ad esempio, il codice seguente mostra come spoglio lo spazio bianco finale solo se arriva dopo un punto e virgola (qui è legato F8).

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

Questo è utile se, come me, hai alcuni file con heredocs simili a markdown intervallati da istruzioni di programmazione con punto e virgola.


6
Cerca :keeppatternsdi evitare l'override @/. E dai anche un'occhiata :keepjumps.
Bohr

@Bohr Quale versione di vim stai usando? Ho provato :help keeppatterne non ho ottenuto nulla.
Christopher Bottoms

@ChristopherBottoms Almeno la versione 7.4.155 .
Bohr,

@Bohr. Grazie! Vieni a scoprire che stavo ancora usando 7.4.0. Ho installato l'ultima versione ed è disponibile.
Christopher Bottoms

2
Puoi ottenere lo stesso effetto racchiudendo questo comando in una funzione, poiché da allora l'ultimo termine di ricerca viene ripristinato automaticamente :-) In questo modo non dovrai preoccuparti di :nohlentrambi, se se stessi evidenziando qualcosa, continuerà a evidenziare (vedi la mia risposta aggiornata).
Martin Tournoij,

175

Il modo "più semplice" è semplicemente usare :substitute:

:%s/\s\+$//e
  • :%sper eseguire :substituteoltre l'intervallo %, che è l'intero buffer.
  • \s t corrisponde a tutti i caratteri degli spazi bianchi.
  • \+ per ripeterli 1 o più volte.
  • $ ancorare alla fine della linea.
  • Il eflag non dà un errore se non c'è corrispondenza (cioè il file è già senza spazi vuoti finali).

Tuttavia, questo non è probabilmente il modo "migliore" in quanto causa due effetti collaterali:

  1. sposta il cursore sull'ultima corrispondenza;
  2. aggiunge il comando alla cronologia e alla cronologia delle ricerche;
  3. reimposta l'ultimo termine di ricerca.

È possibile correggere entrambi gli elementi trasformandolo in una funzione:

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

E poi usalo come:

:call TrimWhitespace()
  1. Il winsaveview()comando salverà la "vista" corrente, che include la posizione del cursore, le pieghe, i salti, ecc. Alla winrestview()fine lo ripristinerà dalla variabile salvata.
  2. Questo :keeppatternsimpedisce che il \s\+$modello venga aggiunto alla cronologia delle ricerche.
  3. L'ultimo termine di ricerca utilizzato viene ripristinato automaticamente dopo aver lasciato una funzione, quindi non dobbiamo fare altro per questo.

Dal momento che è un po 'fastidioso digitare :calltutto il tempo, puoi definire un comando:

command! TrimWhitespace call TrimWhitespace()

Che può essere utilizzato senza :call:

:TrimWitespace

E ovviamente puoi associarlo a una chiave:

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

Ad alcune persone piace farlo automaticamente prima di scrivere un file sul disco, in questo modo:

autocmd BufWritePre * :call TrimWhitespace()

Non mi piace, poiché alcuni formati richiedono spazi vuoti finali (come Markdown) e in alcune altre occasioni desideri persino spazi vuoti finali nel tuo codice (come formattare un'e-mail e usare l' --<Space>indicatore per indicare l'inizio di una firma ).


Modalità plug senza vergogna: qualche tempo fa ho scritto un piccolo script Python per ripulire gli spazi bianchi per un intero progetto contemporaneamente.


1
Se non si desidera creare una funzione per passare alla posizione precedente, è possibile premere ​`​due volte solo al termine della sostituzione. Questo apre la possibilità di creare un oneliner come questo:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel

1
@ NeaţuOvidiuGabriel, ovviamente il doppio backtick non funzionerà allo stesso modo dopo l'esecuzione dell'eliner. ;)
Wildcard il

Simile: stackoverflow.com/a/1618401 . Ma mi piace di più il codice di Martin.
john cj

11

Per eliminare tutti gli spazi bianchi finali (alla fine di ogni riga), è possibile utilizzare il comando:

:%s/ \+$//

Per includere le schede, utilizzare \sinvece di spazio.


Dalla riga di comando:

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

Tutti i file nella directory corrente (usare ricorsivamente **/*.*):

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

Python way:

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

o:

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

Utilizzare lstrip()per la striscia sinistra (dietro), rstrip()per la striscia destra (davanti) o strip()per rimuovere da entrambe le estremità.


Ecco una funzione utile che rimuove lo spazio bianco superfluo dalla fine di una linea che puoi aggiungere al tuo .vimrc:

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

C'è anche il plugin DeleteTrailingWhitespace per questo.


Evidenziando gli spazi bianchi

Per verificare se tutti gli spazi finali sono andati, utilizzare:

  1. Digita / $per trovarli. Se ce ne sono, Vim li evidenzierebbe per te.

  2. Usa i colori per evidenziarli:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Usa caratteri visibili ( fonte ):

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

Vedi anche: Evidenzia spazi indesiderati

Per evidenziare gli spazi bianchi finali per impostazione predefinita, è possibile configurare .vimrccome segue:

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

Rimozione di spazi bianchi per impostazione predefinita

Se desideri assicurarti che tutti gli spazi bianchi finali in un file vengano rimossi automaticamente al momento del salvataggio, puoi aggiungere il seguente comando nel tuo .vimrc:

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

che non è raccomandato, poiché rimuoverà gli spazi bianchi finali da ogni file salvato da un utente (anche dove è possibile desiderare spazi bianchi).


Guarda anche:


5

Scadendo un po 'dalla risposta di Christopher Bottoms : Jonathan Palardy ha scritto un buon articolo su questo . In esso, scrive una funzione, Preserve(command)che conserva lo stato dell'editor (principalmente la posizione del cursore e l'ultimo modello di ricerca) durante l'esecuzione di un comando arbitrario:

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

Questo ha il vantaggio di essere multiuso, ad esempio puoi usarlo per sostituire tutti gli spazi bianchi finali (come fa Jonathan) mappando questo a:

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

Puoi anche usarlo per una mappatura della modalità visiva per rimuovere semplicemente gli spazi finali su linee visivamente selezionate:

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

E puoi usarlo per altre chiamate, come formattare l'intero documento usando =mentre mantieni il tuo posto (usa bene una chiave diversa questa volta per non entrare in conflitto):

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

Tutto sommato, ho trovato la Preserve(command)funzione per essere uno strumento piacevole da avere.


2
L'ultimo termine di ricerca utilizzato deve essere automaticamente preservato quando si lascia una funzione; così @/non dovrebbe essere necessario scherzare con (in questo caso, comunque).
Martin Tournoij,

3
winsaveview()e winrestview()sono di gran lunga superiori.
dash-tom-bang

Giusto! Aggiornato in base al tuo feedback.
Alex

0

Un'altra versione della funzione StripTrailingSpaces:

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

IN REALTÀ C'È UN ERRORE IN QUESTA FUNZIONE (questa): la possessione non viene mantenuta a causa dell'opzione "range". viene rimosso funziona molto bene, tuttavia sto condividendo il codice per ricevere aiuto.

Come puoi vedere usa anche la funzione Preserve vista sopra, ma in modo leggermente diverso.

La differenza qui è che posso selezionare un intervallo di righe o un paragrafo con vipe quindi l'intervallo :'<,'>apparirà automaticamente al prompt dei comandi.

L'idea è nata dal post di Bez Hermoso .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.