除去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}"
从vim调用grep可能需要调整我的正则表达式(例如:remove 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()
    
已邀请:
这种效果可以通过使用子替换特殊替换和
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 _
概述:使用替换将每个匹配按顺序附加到寄存器“a”中,然后用寄存器“a”的内容替换整个缓冲区 说明:
let @a=""
清空我们将要附加的“a”寄存器
%s//=setreg('A', submatch(0), 'l')/g
使用最后一个模式全局替换
=expr
将用表达式的内容替换模式
submatch(0)
获得刚刚匹配的整个字符串
setreg('A', submatch(0), 'l')
追加(注意:大写“a”)到@a匹配的字符串,但是按行
%d _
删除每一行到黑洞寄存器(又名@_)
pu a
将@a的内容放入缓冲区
0d _
删除第一行 关注: 这会丢弃你的一个寄存器。这个例子破坏了@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>).*/1/g
其中
1
是第一个匹配的组(仅地址),
.{-}
用于非贪婪匹配。     
: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=""
:清空寄存器。
gg0
:转到第一行(gg)的第一列(0)。
qa
:开始编写宏。
c/{pattern}<CR>
:改变直到模式。
c{motion}<CR><ESC>
:用换行符替换文本(这里
{motion}
/{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}"
(虽然我实际上投了冰笔的替代答案)     

要回复问题请先登录注册