Удалить все, кроме регулярных выражений в Vim - PullRequest
15 голосов
/ 21 декабря 2010

Мой конкретный случай - это текстовый документ, который содержит много текста и адресов IPv4. Я хочу удалить все, кроме IP-адресов.

Я могу использовать :vglobal для поиска ([0-9]{1,3}\.){3}[0-9]{1,3} и удаления всех строк без IP-адресов, но после этого я знаю только, как искать всю строку и выбирать соответствующий текст. Есть ли более простой способ.

Короче говоря, я ищу способ сделать следующее без использования внешней программы (например, grep):

grep --extended-regexp --only-matching --regexp="([0-9]{1,3}\.){3}[0-9]{1,3}"

Для вызова grep из vim может потребоваться адаптация моего регулярного выражения (например, удаление \ v). Использование инкрементального поиска в vim показывает, что у меня есть правильный шаблон, и я не хочу проверять свое регулярное выражение в grep.


Редактировать: Благодаря Питеру, вот функция, которую я сейчас использую. (C - это регистр, который я обычно использую в своих функциях.)

"" Remove all text except what matches the current search result
"" The opposite of :%s///g (which clears all instances of the current search).
function! ClearAllButMatches()
    let old = @c
    let @c=""
    %s//\=setreg('C', submatch(0), 'l')/g
    %d _
    put c
    0d _
    let @c = old
endfunction

Edit2: Я сделал это командой, которая принимает диапазоны (но по умолчанию весь файл).

"" Remove all text except what matches the current search result. Will put each
"" match on its own line. This is the opposite of :%s///g (which clears all
"" instances of the current search).
function! s:ClearAllButMatches() range
    let is_whole_file = a:firstline == 1 && a:lastline == line('$')

    let old_c = @c

    let @c=""
    exec a:firstline .','. a:lastline .'sub//\=setreg("C", submatch(0), "l")/g'
    exec a:firstline .','. a:lastline .'delete _'
    put! c

    "" I actually want the above to replace the whole selection with c, but I'll
    "" settle for removing the blank line that's left when deleting the file
    "" contents.
    if is_whole_file
        $delete _
    endif

    let @c = old_c
endfunction
command! -range=% ClearAllButMatches <line1>,<line2>call s:ClearAllButMatches()

Ответы [ 4 ]

11 голосов
/ 23 декабря 2010

Этот эффект может быть достигнут с помощью подстановки-специальной замены и setreg(), также

:let @a=""
:%s//\=setreg('A', submatch(0), 'l')/g
:%d _
:pu a
:0d _

или всего в одной строке как таковой:

:let @a=""|%s//\=setreg('A', submatch(0), 'l')/g|%d _|pu a|0d _

Обзор: Использованиезамена для добавления каждого совпадения в регистр «а», а затем замена всего буфера содержимым регистра «а»

Объяснение:

  1. let @a="" пусто «а»зарегистрируйте, что мы будем добавлять в
  2. %s//\=setreg('A', submatch(0), 'l')/g глобальную замену с использованием последнего шаблона
  3. \=expr заменит шаблон содержимым выражения
  4. submatch(0) получить всю строку только что сопоставленного
  5. setreg('A', submatch(0), 'l') добавить (примечание: заглавная "a") к @a сопоставляемой строке, но также
  6. %d _ удалить каждую строку врегистр черной дыры (он же @_)
  7. pu a помещает содержимое @a в буфер
  8. 0d _ удаляет первую строку

Проблемы:

  • Это уничтожит один из ваших регистров.В этом примере trashed @ a
  • используется последний шаблон поиска.Хотя вы можете изменить команду замены любым шаблоном, который вам нужен: %s/<pattern>/\=setreg('A', submatch(0), 'l')/g

Для получения дополнительной помощи

:h :s\=
:h :let-@
:h submatch()
:h setreg()
:h :d
:h :p
6 голосов
/ 21 декабря 2010

Предполагая, что <ip> является вашим регулярным выражением для соответствия IP-адресу, я предполагаю, что вы могли бы сделать что-то вроде:

:%s/.\{-}\(<ip>\).*/\1/g

, где \1 - первая найденная группа (только адрес), а .\{-} - для сопоставления без жадности.

5 голосов
/ 22 декабря 2010
:set nowrapscan
:let @a=""
gg0qac/\v(\d{1,3}\.){3}\d{1,3}<CR><CR><Esc>//e+1<CR>@aq@adG

Объяснение:

  1. set nowrapscan отключает возможность поиска «за концом файла».
  2. let @a="": очистить регистр.
  3. gg0: перейти к первому столбцу (0) первой строки (gg).
  4. qa: начать писать макросы.
  5. c/{pattern}<CR>: изменить до шаблона.
  6. c{motion}<CR><ESC>: заменить текст новой строкой (здесь {motion} is /{pat}<CR>).
  7. //e+1<CR>: найти последний шаблон, пройти один символ слева от его конца (переносывокруг новой строки, но если ваши строки выглядят так: IP<newline>IP, могут возникнуть проблемы).
  8. @a: выполнить макросы @a (пусто, когда вы записываете его, но когда выПо окончании будет повторяться шаги 1-7 до тех пор, пока не возникнет ошибка.
  9. q: завершить запись @a.
  10. @a: выполнить @a макросы.
  11. dG: удалить в конец файла.
4 голосов
/ 22 декабря 2010

Короче, я ищу способ сделать это, не выходя из vim

Достаточно просто:

:1,$! grep --extended-regexp --only-matching --regexp="([0-9]{1,3}\.){3}[0-9]{1,3}"

(хотя я на самом деле проголосовал за замену ответа ледяной преступности)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...