Cách đơn giản nhất để loại bỏ khoảng trắng theo dõi từ tất cả các dòng trong một tệp là gì?


139

Nó khá phổ biến khi lập trình hoặc mở tệp văn bản để gặp các tệp có khoảng trắng ở cuối dòng. vim có một cách để thể hiện điều này bằng cách đặt trailtùy chọn trong listcharstùy chọn và sau đó bật list.

Tuy nhiên, cách dễ nhất để loại bỏ khoảng trắng theo dõi đó trên toàn cầu trên toàn bộ tệp (lý tưởng là không có plugin) là gì?



Đây là một mục tài liệu về chủ đề.
Filipp W.

Nếu bạn đã cài đặt vim-faq , bạn có thể nhận được câu trả lời ngoại tuyến ở đó: :h vim-faqvà tìm kiếm /trailing. Các thẻ khó để ghi nhớ là :h faq-12.1.
Hotschke

Câu trả lời:


72

Sử dụng tổ hợp phím để loại bỏ tất cả các khoảng trắng ở cuối

Vì một số trang mà tôi chỉnh sửa thực sự cần các khoảng trắng theo dõi (ví dụ đánh dấu) và các trang khác thì không, tôi đã thiết lập một phím bấm F5để nó không phải là tự động. Để làm như vậy, hãy thêm mã dưới đây (từ vim.wikia) hoặc một số biến thể của mã này vào .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>thực hiện ánh xạ không hồi quy tới khóa F5ở chế độ bình thường
  • :let _s=@/lưu trữ cụm từ tìm kiếm cuối cùng (từ macro @/) trong biến_s
  • <Bar>Chức năng như một biểu tượng đường ống |để phân tách các lệnh, tuy nhiên |sẽ kết thúc một lệnh trong ngữ cảnh này, do đó <Bar>phải được sử dụng thay thế.
  • :%s/\s\+$//etìm kiếm khoảng trắng theo dõi và xóa nó ở mọi nơi trong bộ đệm (xem câu trả lời của RugSmker để biết chi tiết về biểu thức này)
  • let @/=_sKhôi phục cụm từ tìm kiếm cuối cùng của bạn cho macro @/, để nó sẽ có sẵn vào lần tiếp theo bạn nhấn n.
  • <CR> kết thúc ánh xạ

... hoặc được lựa chọn nhiều hơn

Nếu bạn có trường hợp bạn không muốn loại bỏ tất cả khoảng trắng ở cuối, bạn có thể sử dụng một mẫu để được chọn lọc hơn. Ví dụ, đoạn mã sau chỉ ra cách tôi loại bỏ khoảng trắng theo sau nếu nó xuất hiện sau dấu chấm phẩy (ở đây nó được gắn với F8).

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

Điều này rất hữu ích nếu, giống như tôi, bạn có một số tệp có dấu hiệu giống như heredocs xen kẽ giữa các câu lệnh lập trình chấm dứt dấu chấm phẩy.


6
Cố gắng :keeppatternsngăn chặn ghi đè @/. Và cũng hãy xem :keepjumps.
Bohr

@Bohr Bạn đang sử dụng phiên bản nào của vim? Tôi đã thử :help keeppatternvà không nhận được bất cứ điều gì.
Christopher Bottoms

@ChristopherBottoms Ít nhất là phiên bản 7.4.155 .
Bohr

@Bohr. Cảm ơn! Hãy đến để tìm hiểu tôi vẫn đang sử dụng 7.4.0. Tôi đã cài đặt phiên bản mới nhất và nó có sẵn.
Christopher Bottoms

2
Bạn có thể có được hiệu ứng tương tự bằng cách gói lệnh này trong một hàm, từ đó thuật ngữ tìm kiếm cuối cùng được tự động khôi phục :-) Bằng cách này, bạn không phải làm phiền với :nohlmột trong hai, nếu bạn làm nổi bật một cái gì đó, nó sẽ tiếp tục làm nổi bật nó (xem câu trả lời cập nhật của tôi).
Martin Tournoij

175

Cách "đơn giản nhất" là chỉ sử dụng :substitute:

:%s/\s\+$//e
  • :%sđể chạy :substitutetrên phạm vi %, đó là toàn bộ bộ đệm.
  • \s t phù hợp với tất cả các ký tự khoảng trắng.
  • \+ để lặp lại chúng 1 lần trở lên.
  • $ để neo ở cuối dòng.
  • Các elá cờ để không đưa ra một lỗi nếu không có trận đấu (tức là tập tin là đã không có dấu khoảng trắng).

Tuy nhiên, đây có lẽ không phải là cách "tốt nhất" vì nó gây ra hai tác dụng phụ:

  1. nó di chuyển con trỏ đến trận đấu cuối cùng;
  2. nó thêm lệnh vào lịch sử và lịch sử tìm kiếm;
  3. nó đặt lại cụm từ tìm kiếm cuối cùng.

Bạn có thể sửa cả hai mục bằng cách biến mục này thành hàm:

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

Và sau đó sử dụng nó như:

:call TrimWhitespace()
  1. Các winsaveview()sẽ tiết kiệm được "xem" hiện nay, trong đó bao gồm vị trí con trỏ, nếp gấp, nhảy, vv winrestview()ở cuối sẽ khôi phục này từ biến lưu.
  2. Việc :keeppatternsngăn chặn \s\+$mô hình được thêm vào lịch sử tìm kiếm.
  3. Thuật ngữ tìm kiếm được sử dụng lần cuối được tự động khôi phục sau khi rời khỏi chức năng, vì vậy chúng tôi không phải làm gì khác cho việc này.

Vì điều này hơi khó chịu khi gõ :callmọi lúc, bạn có thể xác định một lệnh:

command! TrimWhitespace call TrimWhitespace()

Mà có thể được sử dụng mà không có :call:

:TrimWitespace

Và tất nhiên bạn có thể liên kết nó với một khóa:

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

Một số người thích tự động làm điều này trước khi họ ghi một tệp vào đĩa, như vậy:

autocmd BufWritePre * :call TrimWhitespace()

Tôi không thích nó, vì một số định dạng yêu cầu khoảng trắng theo dõi (chẳng hạn như Markdown) và trong một số trường hợp khác, bạn thậm chí muốn có khoảng trắng theo sau trong mã của mình (chẳng hạn như định dạng email và sử dụng --<Space>điểm đánh dấu để bắt đầu chữ ký ).


Chế độ cắm không biết xấu hổ: cách đây một thời gian tôi đã viết một đoạn mã Python nhỏ để dọn sạch khoảng trắng cho toàn bộ dự án cùng một lúc.


1
Nếu bạn không muốn tạo một chức năng để di chuyển đến vị trí trước đó, bạn có thể chỉ cần nhấn ​`​hai lần sau khi thay thế kết thúc. Điều này mở ra khả năng tạo ra một oneliner như thế này:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel

1
@ NeaţuOvidiuGabriel, tất nhiên sau đó backtick đôi sẽ không hoạt động như nhau sau khi oneliner được thực thi. ;)
tự đại diện

Tương tự: stackoverflow.com/a/1618401 . Nhưng tôi thích mã của Martin hơn.
john cj

11

Để xóa tất cả các khoảng trắng ở cuối (ở cuối mỗi dòng), bạn có thể sử dụng lệnh:

:%s/ \+$//

Để bao gồm các tab, sử dụng \sthay vì không gian.


Từ dòng lệnh:

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

Tất cả các tệp trong thư mục hiện tại (sử dụng đệ quy **/*.*):

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

Cách Python:

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

hoặc là:

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

Sử dụng lstrip()cho dải bên trái (dấu), rstrip()cho dải bên phải (hàng đầu) hoặc strip()để loại bỏ khỏi cả hai đầu.


Đây là chức năng hữu ích giúp loại bỏ khoảng trắng thừa từ cuối dòng mà bạn có thể thêm vào .vimrc:

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

Ngoài ra còn có plugin DeleteTrailingWhitespace cho điều đó.


Làm nổi bật khoảng trắng

Để kiểm tra lại nếu tất cả các dấu cách đã hết, sử dụng:

  1. / $để tìm chúng. Nếu có một số, vim sẽ làm nổi bật chúng cho bạn.

  2. Sử dụng màu sắc để làm nổi bật chúng:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Sử dụng các ký tự hiển thị ( nguồn ):

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

Xem thêm: Đánh dấu các không gian không mong muốn

Để làm nổi bật khoảng trắng theo sau theo mặc định, bạn có thể định cấu hình .vimrcnhư sau:

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

Xóa các khoảng trắng theo mặc định

Nếu bạn muốn đảm bảo rằng tất cả các khoảng trắng ở cuối tệp sẽ tự động bị xóa khi lưu, bạn có thể thêm lệnh sau vào .vimrc:

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

không được khuyến nghị, vì nó sẽ loại bỏ khoảng trắng theo dõi từ mọi tệp mà người dùng lưu (ngay cả khi có thể muốn có khoảng trắng).


Xem thêm:


5

Xuất hiện trên câu trả lời của Christopher Bottoms một chút : Jonathan Palardy đã viết một bài viết hay về điều này . Trong đó, anh ta viết một hàm, Preserve(command)duy trì trạng thái của trình soạn thảo (chủ yếu là vị trí con trỏ và mẫu tìm kiếm cuối cùng) trong khi chạy một lệnh tùy ý:

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

Điều này có lợi thế là đa mục đích, ví dụ bạn có thể sử dụng nó để thay thế tất cả các khoảng trắng ở cuối (như Jonathan làm) bằng cách ánh xạ này tới:

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

Bạn cũng có thể sử dụng nó cho ánh xạ chế độ trực quan để chỉ xóa các khoảng trắng ở các dòng được chọn trực quan:

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

Và bạn có thể sử dụng nó cho các cuộc gọi khác, như định dạng toàn bộ tài liệu bằng cách =giữ lại vị trí của bạn (lần này cũng sử dụng một khóa khác để không xung đột):

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

Tất cả và tất cả, tôi đã tìm thấy Preserve(command)chức năng là một công cụ tốt để có.


2
Thuật ngữ tìm kiếm được sử dụng cuối cùng sẽ được giữ tự động khi bạn rời khỏi một chức năng; vì vậy @/không nên yêu cầu mucking về (trong trường hợp này, dù sao đi nữa).
Martin Tournoij

3
winsaveview()winrestview()vượt trội hơn nhiều.
dash-tom-bang

Khá đúng! Cập nhật dựa trên phản hồi của bạn.
Alex

0

Một phiên bản khác của Chức năng StripTrailingSpaces:

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

HOẠT ĐỘNG CÓ MỘT BUG TRONG CHỨC NĂNG NÀY (cái này): sở hữu không được nuôi ong vì tùy chọn "phạm vi". Nó được gỡ bỏ, nó hoạt động rất tốt, tuy nhiên tôi đang chia sẻ mã để nhận được sự giúp đỡ.

Như bạn có thể thấy nó cũng sử dụng chức năng Bảo tồn đã thấy ở trên, nhưng theo một cách hơi khác.

Sự khác biệt ở đây là tôi có thể chọn một phạm vi dòng hoặc một đoạn vipvà sau đó phạm vi :'<,'>sẽ tự động xuất hiện tại dấu nhắc lệnh.

Ý tưởng xuất phát từ bài đăng của Bez Hermoso .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.