从缓冲区中删除与所选文本匹配的行

时间:2017-12-12 14:42:27

标签: vim

在分析大型日志文件时,我经常删除包含我认为不相关的文本的行:

:g/whatever/d

有时我发现跨越多行的文本,比如堆栈跟踪。为此,我记录了所采取的步骤(搜索,开始锚点,删除结束锚点)并用100000@q重播该宏。我正在搜索已包含的功能或功能,允许我标记文本并删除包含此文本的所有行。理想情况下,这也适用于块选择。

4 个答案:

答案 0 :(得分:3)

如果我理解你的问题,这个命令应该做你想要的:

:g/NullPointer/,/omitt/d

示例:

之前:

1
2
3
NullPointerException1
4
5
6
omitted
7
NullPointerException2
8
9
omitted
10

后:

1
2
3
7
10

请阅读:h edit-paragraph-join,该命令有很好的解释,您的情况只是将join更改为d

答案 1 :(得分:2)

:g/whatever/d2

将删除whatever行及其后面的行。如果您可以找到始终在第一行中出现的文本,则可以通过将2更改为您需要的任何内容来删除所有以下文本(如果它具有相同的行数)。

答案 2 :(得分:2)

你实际上可以在全局命令中使用一些普通命令来实现你想要的,看看你的例子(希望我理解它或多或少):

someText
NullPointerException
...
omitted

您希望从NPE上方的行中删除,直到omitted的行正确? 只需使用以下内容:

:g/NullPointerException/execute "normal! kddd/omitted\<cr>dd"

它可能看起来很复杂,但事实并非如此。它并不比宏 1 更好 ,但我更喜欢命令,因为我总是记录宏的错误。

由于它只使用普通的vim运动,因此很容易采用。如果你f.e.不知道您以前的锚点在哪里,您可以使用?anchor\<cr>代替kd。为了更好的演示,你必须提交一个现实的例子。

[1]你可以说,这只需要运行一次,但对于递归宏http://vim.wikia.com/wiki/Record_a_recursive_macro

也是如此。

答案 3 :(得分:1)

感谢这里的答案,我能够编写一个非常方便的函数:下面的源代码可以选择文本并删除当前缓冲区中具有相同(或类似)文本的所有行。这适用于在线和多线选择。正如我所说,我正在寻找能够让我更快地分析日志文件的东西。日志文件通常包含日期和时间,并且这些日期和时间一直在变化,因此最好有一些让我们忽略数字的东西。让我们来看看。我正在使用这两个映射:

vnoremap d :<C-U>echo RemoveSelectionFromBuffer(0)<CR>
vnoremap D :<C-U>echo RemoveSelectionFromBuffer(1)<CR>

典型用法:

  • 删除忽略数字的类似行: Shift + v ,然后 Shift + d
  • 删除相同的匹配(单行):标记文本内联(不包括日期和时间),然后 d
  • 删除相同的匹配项(多行):在行间标记文字(省略日期和时间),然后 d

这是源代码:

" Removes lines matching the selected text from buffer.
function! RemoveSelectionFromBuffer(ignoreNumbers)
    let lines = GetVisualSelection() " selected lines
    " Escape backslashes and slashes (delimiters)
    call map(lines, {k, v -> substitute(v, '\\\|/', '\\&', 'g')})
    if a:ignoreNumbers == 1
        " Substitute all numbers with \s*\d\s* - in formatted output matching
        " lines may have whitespace instead of numbers. All backslashes need
        " to be escaped because \V (very nomagic) will be used.
        call map(lines, {k, v -> substitute(v, '\s*\d\+\s*', '\\s\\*\\d\\+\\s\\*', 'g')})
    endif
    let blc = line('$') " number of lines in buffer (before deletion)
    let vlc = len(lines) " number of selected lines
    let pattern = join(lines, '\_.') " support multiline patterns
    let cmd = ':g/\V' . pattern . '/d_' . vlc " delete matching lines (d_3)
    let pos = getpos('v') " save position
    execute "silent " . cmd
    call setpos('.', pos) " restore position
    let dlc = blc - line('$') " number of deleted lines
    let dmc = dlc / vlc " number of deleted matches
    let cmd = substitute(cmd, '\(.\{50\}\).*', '\1...', '') " command output
    let lout = dlc . ' line' . (dlc == 1 ? '' : 's')
    let mout = '(' . dmc . ' match' . (dmc == 1 ? '' : 'es') . ')'
    return printf('%s removed: %s', (vlc == 1 ? lout : lout . ' ' . mout), cmd)
endfunction

我从this answer获取了GetVisualSelection()代码。

function! GetVisualSelection()
    if mode() == "v"
        let [line_start, column_start] = getpos("v")[1:2]
        let [line_end, column_end] = getpos(".")[1:2]
    else
        let [line_start, column_start] = getpos("'<")[1:2]
        let [line_end, column_end] = getpos("'>")[1:2]
    end
    if (line2byte(line_start)+column_start) > (line2byte(line_end)+column_end)
        let [line_start, column_start, line_end, column_end] =
        \   [line_end, column_end, line_start, column_start]
    end
    let lines = getline(line_start, line_end)
    if len(lines) == 0
            return ''
    endif
    let lines[-1] = lines[-1][: column_end - 1]
    let lines[0] = lines[0][column_start - 1:]
    return lines
endfunction

谢谢,aepksbuck,DoktorOSwaldo和Kent。