¿Cuál es la forma más simple de eliminar espacios en blanco al final de todas las líneas en un archivo?

139

Es bastante común al programar o abrir archivos de texto para encontrar archivos con espacios en blanco al final de una línea. vim tiene una manera de mostrar esto configurando la trailopción en la listcharsopción y luego activando list.

Sin embargo, ¿cuál es la forma más fácil de eliminar ese espacio en blanco final a nivel mundial en todo el archivo (idealmente sin un complemento)?

Andrew Ferrier
fuente
Aquí hay una entrada de documento sobre el tema.
Filipp
Si ha instalado vim-faq , puede obtener una respuesta sin conexión allí: :h vim-faqy buscar /trailing. La etiqueta difícil de memorizar es :h faq-12.1.
Hotschke

Respuestas:

72

Use una combinación de teclas para eliminar todos los espacios en blanco finales

Dado que algunas páginas que edito realmente necesitan espacios en blanco al final (por ejemplo, markdown) y otras no, configuré una combinación de teclas para F5que sea trivial hacerlo sin ser automático. Para hacerlo, agregue el siguiente código (de vim.wikia) o alguna variación del mismo a su .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>realiza una asignación no recursiva a la tecla F5en modo normal
  • :let _s=@/almacena el último término de búsqueda (de la macro @/) en la variable_s
  • <Bar>Funciona como un símbolo de tubería |para separar comandos, sin embargo |, terminaría un comando en este contexto, por lo que <Bar>debe usarse en su lugar.
  • :%s/\s\+$//ebusca espacios en blanco finales y los elimina en todas partes en el búfer (consulte la respuesta de CarpetSmoker para obtener un desglose detallado de esta expresión)
  • let @/=_srestaura su último término de búsqueda a la macro @/, para que esté disponible la próxima vez que presione n.
  • <CR> termina el mapeo

... o ser más selectivo

Si tiene casos en los que no desea eliminar todo el espacio en blanco al final, puede usar un patrón para ser más selectivo. Por ejemplo, el siguiente código muestra cómo elimino los espacios en blanco finales solo si viene después de un punto y coma (aquí está vinculado a F8).

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

Esto es útil si, como yo, tiene algunos archivos con heredocs con marcas reducidas intercalados entre sentencias de programación terminadas en punto y coma.

Christopher Bottoms
fuente
66
Intenta :keeppatternsevitar anular @/. Y también eche un vistazo :keepjumps.
Bohr
@Bohr ¿Qué versión de vim estás usando? Lo intenté :help keeppatterny no obtuve nada.
Christopher Bottoms
@ChristopherBottoms Al menos la versión 7.4.155 .
Bohr
@Bohr. ¡Gracias! Ven a descubrir que todavía estaba usando 7.4.0. Instalé la última versión y está disponible.
Christopher Bottoms
2
Puede obtener el mismo efecto envolviendo este comando en una función, ya que luego el último término de búsqueda se restaura automáticamente :-) De esta manera no tiene que molestarse :nohltampoco, si resalta algo, seguirá resaltando. (ver mi respuesta actualizada).
Martin Tournoij
175

La forma "más simple" es simplemente usar :substitute:

:%s/\s\+$//e
  • :%sejecutar :substitutesobre el rango %, que es todo el búfer.
  • \s t coincide con todos los espacios en blanco.
  • \+ repetirlos 1 o más veces.
  • $ para anclar al final de la línea.
  • La emarca para no dar un error si no hay coincidencia (es decir, el archivo ya no tiene espacios en blanco al final).

Sin embargo, esta probablemente no sea la "mejor" forma ya que causa dos efectos secundarios:

  1. mueve el cursor al último partido;
  2. agrega el comando al historial y al historial de búsqueda;
  3. restablece el último término de búsqueda.

Puede arreglar ambos elementos convirtiéndolo en una función:

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

Y luego úsalo como:

:call TrimWhitespace()
  1. El winsaveview()guardará la "vista" actual, que incluye la posición del cursor, pliegues, saltos, etc. Al winrestview()final, se restaurará esto desde la variable guardada.
  2. Esto :keeppatternsevita que el \s\+$patrón se agregue al historial de búsqueda.
  3. El último término de búsqueda utilizado se restaura automáticamente después de dejar una función, por lo que no tenemos que hacer nada más para esto.

Dado que esto es algo molesto de escribir :calltodo el tiempo, puede definir un comando:

command! TrimWhitespace call TrimWhitespace()

Que se puede usar sin :call:

:TrimWitespace

Y, por supuesto, puede vincularlo a una clave:

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

A algunas personas les gusta hacer esto automáticamente antes de escribir un archivo en el disco, así:

autocmd BufWritePre * :call TrimWhitespace()

No me gusta, ya que algunos formatos requieren espacios en blanco finales (como Markdown), y en otras ocasiones incluso desea espacios en blanco finales en su código (como formatear un correo electrónico y usar el --<Space>marcador para indicar el inicio de una firma )


Modo de enchufe descarado: hace un tiempo escribí un pequeño script de Python para limpiar los espacios en blanco de un proyecto completo a la vez.

Martin Tournoij
fuente
1
Si no desea crear una función para moverse a la posición anterior, puede presionar ​`​dos veces después de que termine el reemplazo. Esto abre la posibilidad de crear una línea como esta:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel
1
@ NeaţuOvidiuGabriel, por supuesto, el doble backtick no funcionará igual después de que se ejecute el oneliner. ;)
Comodín el
Similar: stackoverflow.com/a/1618401 . Pero me gusta más el código de Martin.
John cj
11

Para eliminar todos los espacios en blanco finales (al final de cada línea), puede usar el comando:

:%s/ \+$//

Para incluir pestañas, use en \slugar de espacio.


Desde la línea de comandos:

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

Todos los archivos en el directorio actual (uso recursivo **/*.*):

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

Forma de Python:

: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()

Úselo lstrip()para la tira izquierda (posterior), rstrip()para la tira derecha (delantera) o strip()para quitar de ambos extremos.


Aquí hay una función útil que elimina el espacio en blanco superfluo del final de una línea que puede agregar a su .vimrc:

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

También hay un complemento DeleteTrailingWhitespace para eso.


Destacando espacios en blanco

Para verificar si todos los espacios finales se han ido, use:

  1. Escribe / $para encontrarlos. Si hay algunos, vim los destacaría por usted.

  2. Usa colores para resaltarlos:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Usar caracteres visibles ( fuente ):

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

Ver también: resaltar espacios no deseados

Para resaltar los espacios en blanco finales de forma predeterminada, puede configurar su de la .vimrcsiguiente manera:

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

Eliminar espacios en blanco por defecto

Si desea asegurarse de que todos los espacios en blanco al final de un archivo se eliminen automáticamente al guardar, puede agregar el siguiente comando a su .vimrc:

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

lo cual no se recomienda, ya que eliminará los espacios en blanco al final de cada archivo que guarde un usuario (incluso donde se pueda desear espacios en blanco).


Ver también:

kenorb
fuente
5

Ampliando un poco la respuesta de Christopher Bottoms : Jonathan Palardy escribió un buen artículo sobre esto . En él, escribe una función, Preserve(command)que conserva el estado del editor (principalmente la posición del cursor y el último patrón de búsqueda) mientras ejecuta 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

Esto tiene la ventaja de ser multipropósito, por ejemplo, puede usarlo para reemplazar todos los espacios en blanco finales (como lo hace Jonathan) al asignar esto a:

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

También puede usarlo para un mapeo en modo visual para eliminar los espacios finales en las líneas visualmente seleccionadas:

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

Y puede usarlo para otras llamadas, como formatear todo el documento =mientras conserva su lugar (esta vez use una clave diferente para no entrar en conflicto):

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

En general, he encontrado que la Preserve(command)función es una buena herramienta para tener.

Alex
fuente
2
El último término de búsqueda utilizado debe conservarse automáticamente cuando abandona una función; por lo tanto @/, no debería ser necesario jugar con (en este caso, de todos modos).
Martin Tournoij
3
winsaveview()y winrestview()son muy superiores
dash-tom-bang
¡Muy bien! Actualizado según sus comentarios.
Alex
0

Otra versión de la función StripTrailingSpaces:

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

REALMENTE HAY UN ERROR EN ESTA FUNCIÓN (esta): la posición no se mantiene debido a la opción de "rango". Si se elimina, funciona muy bien, sin embargo, estoy compartiendo el código para recibir ayuda.

Como puede ver, también utiliza la función Conservar vista anteriormente, pero de una manera ligeramente diferente.

La diferencia aquí es que puedo seleccionar un rango de líneas o un párrafo con vipy luego el rango :'<,'>aparecerá automáticamente en el símbolo del sistema.

La idea surgió del post de Bez Hermoso .

SergioAraujo
fuente