Удалить все, кроме regex match в Vim
мой конкретный случай-это текстовый документ, который содержит много текста и адресов 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.
Edit: благодаря Питеру, вот функция, которую я сейчас использую. (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 ответов
этот эффект может быть достигнут с помощью sub-replace-special substitution и setreg()
linewise
: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 _
обзор: используя подстановку, чтобы добавить каждое совпадение в регистр "a", линейно замените весь буфер содержимым регистра"a"
объяснение:
-
let @a=""
очистите регистр" a", который мы будем добавлять в -
%s//\=setreg('A', submatch(0), 'l')/g
замените глобально, используя последний шаблон - the
\=expr
заменит шаблон содержимым выражения -
submatch(0)
получить всю строку того, что только что совпало -
setreg('A', submatch(0), 'l')
добавить (примечание: заглавная "a") в @A согласованную строку, но линейно -
%d _
удалить каждую строку в регистр черных дыр (он же @_) -
pu a
поместите содержимое @a в буфер -
0d _
удалить первая строка
проблемы:
- это будет мусор один из ваших регистров. Этот пример trashed @a
- использует последний шаблон поиска. Хотя вы можете изменить команду замены с любым шаблоном, который вы хотите:
%s/<pattern>/\=setreg('A', submatch(0), 'l')/g
для получения дополнительной помощи
:h :s\=
:h :let-@
:h submatch()
:h setreg()
:h :d
:h :p
предполагая, что <ip>
ваше регулярное выражение для соответствия IP-адресу, я полагаю, вы могли бы сделать что-то вроде :
:%s/.\{-}\(<ip>\).*//g
здесь является первой сопоставленной группой (только адрес), и
.\{-}
используется для не жадного сопоставления.
:set nowrapscan
:let @a=""
gg0qac/\v(\d{1,3}\.){3}\d{1,3}<CR><CR><Esc>//e+1<CR>@aq@adG
объяснение:
-
set nowrapscan
отключает возможность поиска "после окончания файла". -
let @a=""
: очистите регистр a. -
gg0
: перейдите в первую колонку (0) первой строки (gg). -
qa
: начать писать макросы. -
c/{pattern}<CR>
: изменить, пока узор. -
c{motion}<CR><ESC>
: заменить текст новой строкой (здесь{motion}
is/{pat}<CR>
). -
//e+1<CR>
: поиск последнего шаблона, перейти один символ, оставленный за его концом (обертывает новую строку, но если ваши строки выглядят так:IP<newline>IP
, могут возникнуть проблемы). -
@a
выполнить@a
макросы (он пуст, когда вы записываете его, но когда вы закончите, он будет повторять шаги 1-7, пока не получит ошибку). -
q
: прекратить запись@a
. -
@a
выполнить@a
макросы. -
dG
: удалить до конца файла.
короче говоря, я ищу способ сделать это, не выходя из vim
достаточно просто:
:1,$! grep --extended-regexp --only-matching --regexp="([0-9]{1,3}\.){3}[0-9]{1,3}"
(хотя я фактически проголосовал за ответ замены icecrime)