Какой самый простой способ убрать конечные пробелы из всех строк в файле?

139

При программировании или открытии текстовых файлов довольно часто встречаются файлы с конечным пробелом в конце строки. У vim есть способ показать это, установив trailопцию в listcharsопции и затем включив list.

Тем не менее, каков самый простой способ устранить этот пробел в глобальном масштабе по всему файлу (в идеале без плагина)?

Эндрю Ферье
источник
Вот документация по теме.
Филипп В.
Если вы установили vim-faq , вы можете получить оффлайн ответ: :h vim-faqи искать /trailing. Трудно запомнить тег :h faq-12.1.
Хотчке

Ответы:

72

Используйте связывание клавиш, чтобы убрать все конечные пробелы

Так как некоторые страницы, которые я редактирую, на самом деле нуждаются в конечных пробелах (например, уценке), а другие нет, я установил привязку к клавишам F5так, чтобы это было тривиально, не будучи автоматическим. Для этого добавьте приведенный ниже код (из vim.wikia) или его разновидность .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>выполняет нерекурсивное сопоставление с ключом F5в обычном режиме
  • :let _s=@/сохраняет последний поисковый запрос (из макроса @/) в переменной_s
  • <Bar>Функционирует как символ канала |для разделения команд, однако |в этом контексте завершает команду, поэтому <Bar>должен использоваться вместо этого.
  • :%s/\s\+$//eищет конечные пробелы и удаляет их повсюду в буфере ( подробный анализ этого выражения см. в ответе CarpetSmoker )
  • let @/=_sвосстанавливает ваш последний поисковый запрос в макросе @/, чтобы он был доступен при следующем нажатии n.
  • <CR> заканчивает отображение

... или быть более избирательным

Если у вас есть случаи, когда вы не хотите убирать все конечные пробелы, вы можете использовать шаблон, чтобы быть более избирательным. Например, следующий код показывает, как я удаляю конечные пробелы, только если они идут после точки с запятой (здесь она связана с F8).

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

Это полезно, если, как и у меня, у вас есть некоторые файлы с heredocs, подобными markdown, перемежающиеся между запятыми точкой с запятой.

Кристофер Боттомс
источник
6
Попробуйте :keeppatternsпредотвратить переопределение @/. А также взглянуть на :keepjumps.
Бор
@Bohr Какую версию vim вы используете? Я пытался :help keeppatternи ничего не получил.
Кристофер Боттомс
@ChristopherBottoms По крайней мере, версия 7.4.155 .
Бор
@Bohr. Спасибо! Приходите, чтобы узнать, что я все еще использую 7.4.0. Я установил последнюю версию, и она доступна.
Кристофер Боттомс
2
Вы можете получить тот же эффект, заключив эту команду в функцию, так как после этого последний поисковый термин автоматически восстанавливается :-) Таким образом, вам не нужно ничего путать с :nohlлюбым из них, если, если вы что-то подсвечивали, он продолжит подсвечивать это (см. мой обновленный ответ).
Мартин Турной
175

Самый простой способ - просто использовать :substitute:

:%s/\s\+$//e
  • :%sработать :substituteнад диапазоном %, который является всем буфером.
  • \s не соответствует всем пробельным символам.
  • \+ повторить их 1 или более раз.
  • $ закрепить в конце линии.
  • eФлаг не выдаст ошибку , если нет совпадения (то есть файл уже без конечных пробелов).

Однако это, вероятно, не самый лучший способ, поскольку он вызывает два побочных эффекта:

  1. перемещает курсор к последнему совпадению;
  2. добавляет команду в историю и историю поиска;
  3. он сбрасывает последний поисковый запрос.

Вы можете исправить оба элемента, превратив это в функцию:

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

И затем используйте это как:

:call TrimWhitespace()
  1. winsaveview()Сохранят текущий «вид», который включает в себя положение курсора, складывает, скачет и т.д. winrestview()в конце будет восстановить это из сохраненных переменных.
  2. :keeppatternsПредотвращает \s\+$образец от добавления в истории поиска.
  3. Последний использованный поисковый термин автоматически восстанавливается после выхода из функции, поэтому нам не нужно ничего делать для этого.

Так как вводить текст постоянно раздражает :call, вы можете определить команду:

command! TrimWhitespace call TrimWhitespace()

Который может быть использован без :call:

:TrimWitespace

И вы можете, конечно, связать его с ключом:

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

Некоторым людям нравится делать это автоматически перед записью файла на диск, например так:

autocmd BufWritePre * :call TrimWhitespace()

Мне это не нравится, так как некоторые форматы требуют конечного пробела (например, Markdown), а в некоторых других случаях вы даже хотите использовать конечный пробел в своем коде (например, форматирование электронного письма и использование --<Space>маркера для указания начала подписи). ).


Бесстыдный режим плагинов: некоторое время назад я написал небольшой скрипт на Python для очистки пробелов сразу для всего проекта.

Мартин Турной
источник
1
Если вы не хотите создавать функцию для перемещения в предыдущую позицию, вы можете просто нажать ​`​дважды после завершения замены. Это открывает возможность для создания oneliner, как это:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel
1
@ NeaţuOvidiuGabriel, разумеется, двойной бэкстик не будет работать так же после выполнения oneliner. ;)
Wildcard
Похоже: stackoverflow.com/a/1618401 . Но мне больше нравится код Мартина.
Джон CJ
11

Чтобы удалить все конечные пробелы (в конце каждой строки), вы можете использовать команду:

:%s/ \+$//

Чтобы включить вкладки, используйте \sвместо пробела.


Из командной строки:

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

Все файлы в текущем каталоге (рекурсивно использовать **/*.*):

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

Python путь:

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

или же:

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

Используйте lstrip()для левой полосы (задней), rstrip()для правой полосы (ведущей) или strip()для удаления с обоих концов.


Вот полезная функция, которая удаляет лишние пробелы в конце строки, которые вы можете добавить к своей .vimrc:

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

Для этого есть также плагин DeleteTrailingWhitespace .


Подсветка пробелов

Чтобы перепроверить все ли пробелы в конце, используйте:

  1. Типа, / $чтобы найти их. Если они есть, vim выделит их для вас.

  2. Используйте цвета, чтобы выделить их:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Используйте видимые символы ( источник ):

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

Смотрите также: выделите ненужные места

Чтобы выделить конечные пробелы по умолчанию, вы можете настроить .vimrcследующие параметры:

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

Удаление пробелов по умолчанию

Если вы хотите убедиться, что все конечные пробелы в файле автоматически удаляются при сохранении, вы можете добавить следующую команду в свой .vimrc:

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

что не рекомендуется, так как он удаляет конечные пробелы из каждого файла, который пользователь сохраняет (даже там, где пробелы могут быть желательны).


Смотрите также:

kenorb
источник
5

Немного поясняю ответ Кристофера Боттомса : Джонатан Паларди написал хорошую статью на эту тему . В нем он пишет функции, Preserve(command)которые сохраняют состояние редактора (главным образом, положение курсора и последний шаблон поиска) при выполнении произвольной команды:

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

Это имеет многоцелевое преимущество, например, вы можете использовать его для замены всех конечных пробелов (как это делает Джонатан), сопоставив это с:

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

Вы также можете использовать его для отображения в визуальном режиме, чтобы просто удалить конечные пробелы в визуально выбранных строках:

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

И вы можете использовать его для других вызовов, например, для форматирования всего документа =, сохраняя свое место (на этот раз используйте другой ключ, чтобы не конфликтовать):

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

В общем, я обнаружил, что эта Preserve(command)функция - хороший инструмент.

Alex
источник
2
Последний использованный поисковый термин должен автоматически сохраняться при выходе из функции; поэтому @/не нужно требовать дурака (в любом случае, в этом случае).
Мартин Турной
3
winsaveview()и winrestview()намного выше.
dash-tom-bang
Совершенно верно! Обновлено на основе ваших отзывов.
Алекс
0

Другая версия функции StripTrailingSpaces:

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

В действительности это ошибка в этой функции (эта): возможность не сохраняется из-за опции «range». если он удален, он работает очень хорошо, однако я делюсь кодом, чтобы получить некоторую помощь.

Как вы можете видеть, он также использует функцию сохранения, показанную выше, но немного по-другому.

Разница здесь в том, что я могу выбрать диапазон строк или абзац с помощью, vipи тогда диапазон :'<,'>автоматически появится в командной строке.

Идея пришла из поста Без Эрмосо .

SergioAraujo
источник