Jaki jest najprostszy sposób na usunięcie spacji końcowych ze wszystkich linii w pliku?

139

Jest to dość powszechne podczas programowania lub otwierania plików tekstowych w celu napotkania plików z końcowymi spacjami na końcu linii. vim ma sposób to pokazać, ustawiając trailopcję w listcharsopcji, a następnie włączając listją.

Jaki jest jednak najłatwiejszy sposób na wyeliminowanie tej spacji na całym świecie w całym pliku (najlepiej bez wtyczki)?

Andrew Ferrier
źródło
Oto wpis w dokumencie na temat.
Filipp W.,
Jeśli zainstalowałeś vim-faq , możesz tam uzyskać odpowiedź offline: :h vim-faqi wyszukać /trailing. Trudno zapamiętać tag :h faq-12.1.
Hotschke

Odpowiedzi:

72

Użyj skrótu klawiszowego, aby usunąć wszystkie końcowe białe znaki

Ponieważ niektóre strony, które edytuję, faktycznie wymagają spacji końcowych (np. Markdown), a inne nie, skonfigurowałem przypisywanie klawiszy, aby F5było to trywialne, nie będąc automatycznym. Aby to zrobić, dodaj poniższy kod (z vim.wikia) lub jego odmianę do .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>wykonuje nierekurencyjne mapowanie na klucz F5w trybie normalnym
  • :let _s=@/przechowuje ostatni szukany termin (z makra @/) w zmiennej_s
  • <Bar>Działa jako symbol potoku |do oddzielania poleceń, jednak |zakończyłby polecenie w tym kontekście, dlatego <Bar>należy go użyć.
  • :%s/\s\+$//ewyszukuje końcowe białe znaki i usuwa je wszędzie w buforze (zobacz odpowiedź CarpetSmoker, aby uzyskać szczegółowy podział tego wyrażenia)
  • let @/=_sprzywraca ostatnie wyszukiwane hasło do makra @/, dzięki czemu będzie dostępne przy następnym naciśnięciu n.
  • <CR> kończy mapowanie

... lub być bardziej selektywnym

Jeśli masz przypadki, w których nie chcesz usuwać wszystkich końcowych białych znaków, możesz użyć wzorca, aby być bardziej selektywnym. Na przykład poniższy kod pokazuje, jak usuwam końcowe białe znaki tylko wtedy, gdy następuje po średniku (tutaj jest związany F8).

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

Jest to przydatne, jeśli, podobnie jak ja, masz jakieś pliki z heredokami podobnymi do markdown, rozproszonymi między zakończonymi średnikami instrukcjami programowania.

Christopher Bottoms
źródło
6
Staraj :keeppatternssię zapobiec zastąpieniu @/. A także spójrz na :keepjumps.
Bohr
@Bohr Jakiej wersji vima używasz? Próbowałem :help keeppatterni nic nie dostałem.
Christopher Bottoms
@ChristopherBottoms Przynajmniej wersja 7.4.155 .
Bohr
@Bohr. Dzięki! Dowiedz się, że nadal korzystam z wersji 7.4.0. Zainstalowałem najnowszą wersję i jest ona dostępna.
Christopher Bottoms
2
Możesz uzyskać ten sam efekt, zawijając to polecenie w funkcji, ponieważ odtąd ostatnie wyszukiwane hasło jest automatycznie przywracane :-) W ten sposób nie musisz się obijać :nohl, jeśli jeśli coś zaznaczasz, będzie ono nadal podświetlane to (zobacz moją zaktualizowaną odpowiedź).
Martin Tournoij,
175

„Najprostszym” sposobem jest po prostu użycie :substitute:

:%s/\s\+$//e
  • :%sdo uruchomienia :substitutew zakresie %, który jest całym buforem.
  • \s dopasuj wszystkie znaki spacji.
  • \+ powtarzać je 1 lub więcej razy.
  • $ zakotwiczyć na końcu linii.
  • eFlaga nie dać błąd, jeśli nie ma odpowiednika (czyli plik jest już bez końcowe spacje).

Jednak prawdopodobnie nie jest to „najlepszy” sposób, ponieważ powoduje dwa skutki uboczne:

  1. przesuwa kursor do ostatniego dopasowania;
  2. dodaje polecenie do historii i historii wyszukiwania;
  3. resetuje ostatni wyszukiwany termin.

Możesz naprawić oba elementy, zmieniając to w funkcję:

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

A następnie użyj go w następujący sposób:

:call TrimWhitespace()
  1. winsaveview()Będzie zapisać aktualną „Widok”, który zawiera pozycję kursora, fałdy, skoki itp winrestview()na końcu przywróci to od zapisanego zmiennej.
  2. :keeppatternsZapobiega \s\+$wzorzec z dodawanych do historii wyszukiwania.
  3. Ostatnio używane wyszukiwane hasło jest automatycznie przywracane po opuszczeniu funkcji, więc nie musimy nic więcej robić w tym celu.

Ponieważ ciągłe pisanie jest dość denerwujące :call, możesz zdefiniować polecenie:

command! TrimWhitespace call TrimWhitespace()

Które mogą być używane bez :call:

:TrimWitespace

I oczywiście możesz powiązać go z kluczem:

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

Niektóre osoby lubią to robić automatycznie przed zapisaniem pliku na dysku, na przykład:

autocmd BufWritePre * :call TrimWhitespace()

Nie podoba mi się to, ponieważ niektóre formaty wymagają spacji końcowych (takich jak Markdown), a przy innych okazjach chcesz nawet spacji końcowych w kodzie (takich jak formatowanie wiadomości e-mail i użycie --<Space>znacznika do wskazania początku podpisu ).


Bezwstydny tryb wtyczki: jakiś czas temu napisałem mały skrypt Pythona, aby wyczyścić białe znaki dla całego projektu naraz.

Martin Tournoij
źródło
1
Jeśli nie chcesz tworzyć funkcji, aby przejść do poprzedniej pozycji, możesz po prostu nacisnąć ​`​dwa razy po zakończeniu zamiany. Otwiera to możliwość stworzenia takiego onelinera:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel
1
@ NeaţuOvidiuGabriel, oczywiście wtedy podwójny backtick nie będzie działał tak samo po wykonaniu onelinera. ;)
Wildcard,
Podobne: stackoverflow.com/a/1618401 . Ale bardziej podoba mi się kod Martina.
john cj
11

Aby usunąć wszystkie końcowe białe znaki (na końcu każdej linii), możesz użyć polecenia:

:%s/ \+$//

Aby dołączyć tabulatory, użyj \szamiast spacji.


Z wiersza polecenia:

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

Wszystkie pliki w bieżącym katalogu (użyj rekurencyjnie **/*.*):

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

Sposób Pythona:

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

lub:

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

Użyj lstrip()do lewego paska (wleczonego), rstrip()do prawego paska (prowadzącego) lub strip()do usunięcia z obu końców.


Oto przydatna funkcja, która usuwa zbędne białe znaki z końca linii, którą możesz dodać do swojego .vimrc:

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

Do tego jest również wtyczka DeleteTrailingWhitespace .


Podkreślanie białych znaków

Aby dokładnie sprawdzić, czy zniknęły wszystkie spacje końcowe, użyj:

  1. Wpisz, / $aby je znaleźć. Jeśli są jakieś, vim podświetli je dla ciebie.

  2. Użyj kolorów, aby je podświetlić:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Użyj widocznych znaków ( źródło ):

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

Zobacz także: Podkreśl niechciane miejsca

Aby domyślnie wyróżnić końcowe białe znaki, możesz skonfigurować .vimrcnastępujące czynności:

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

Domyślnie usuwa białe spacje

Jeśli chcesz się upewnić, że wszystkie końcowe białe znaki w pliku są automatycznie usuwane podczas zapisywania, możesz dodać następujące polecenie do .vimrc:

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

co nie jest zalecane, ponieważ spowoduje usunięcie końcowych spacji z każdego pliku zapisywanego przez użytkownika (nawet tam, gdzie może być wymagana biała spacja).


Zobacz też:

kenorb
źródło
5

Trochę rozumiejąc odpowiedź Christophera Bottomsa : Jonathan Palardy napisał na ten temat dobry artykuł . W nim pisze funkcje, Preserve(command)które zachowują stan edytora (głównie pozycję kursora i wzorzec ostatniego wyszukiwania) podczas wykonywania dowolnego polecenia:

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

Ma to tę zaletę, że jest uniwersalne, na przykład można go użyć do zastąpienia wszystkich spacji końcowych (tak jak robi to Jonathan), odwzorowując to na:

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

Możesz go również użyć do mapowania trybu wizualnego, aby po prostu usunąć końcowe spacje na wizualnie wybranych liniach:

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

I możesz go używać do innych połączeń, takich jak formatowanie całego dokumentu przy =zachowaniu swojego miejsca (tym razem użyj innego klucza, aby uniknąć konfliktu):

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

W sumie uważam, że ta Preserve(command)funkcja jest przyjemnym narzędziem.

Alex
źródło
2
Ostatnio używane wyszukiwane hasło powinno zostać automatycznie zachowane po opuszczeniu funkcji; więc @/nie powinno się wymagać rozmyślania z (w tym przypadku i tak).
Martin Tournoij,
3
winsaveview()i winrestview()są o wiele lepsze.
dash-tom-bang
Całkiem dobrze! Zaktualizowano na podstawie Twojej opinii.
Alex
0

Inna wersja funkcji StripTrailingSpaces:

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

AKTUALNIE JEST BŁĄD W TEJ FUNKCJI (tej): opcja nie jest utrzymywana z powodu opcji „zasięgu”. po usunięciu działa bardzo dobrze, jednak udostępniam kod, aby uzyskać pomoc.

Jak widać, wykorzystuje on także funkcję Zachowaj widoczną powyżej, ale w nieco inny sposób.

Różnica polega na tym, że mogę wybrać zakres linii lub akapitu za pomocą, vipa następnie zakres :'<,'>pojawi się automatycznie w wierszu polecenia.

Pomysł pochodzi z postu Bez Hermoso .

SergioAraujo
źródło