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

rlcwz9us  于 2023-01-06  发布在  其他
关注(0)|答案(4)|浏览(144)

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

:g/whatever/d

有时候我会发现文本跨越多行,比如stacktraces。为此,我记录下所采取的步骤(search,go to start锚,delete to end anchor),然后用100000@q重新运行那个宏。我正在搜索vim已经包含的一个函数或特性,它允许我标记文本并删除包含该文本的所有行。理想情况下,这也适用于块选择。

hwamh0ep

hwamh0ep1#

如果我没理解错你的问题,这个命令应该能完成你想要的任务:

: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

yvt65v4c

yvt65v4c2#

:g/whatever/d2

将删除包含whatever的行及其后面的行。如果您可以找到总是出现在第一行的文本,则可以通过将2更改为您需要的任何值来去除后面所有具有相同行数的文本。

3xiyfsfu

3xiyfsfu3#

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

someText
NullPointerException
...
omitted

你想从NPE上面的行删除到omitted的行,对吗?

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

它可能看起来很复杂,但实际上并不复杂。它并不比宏好,但我更喜欢命令,因为我在录制宏时总是出错。
因为它只使用正常的vim动作,所以很容易采用。如果你不知道你以前的锚在哪里,你可以使用?anchor\<cr>代替kd。为了更好地演示,你必须提交一个现实的例子。
[1]您可能会说,这只需要运行一次,但对于递归宏http://vim.wikia.com/wiki/Record_a_recursive_macro也是如此

lndjwyie

lndjwyie4#

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

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

典型用法:

  • 删除忽略数字的类似行:Shift+v,然后Shift+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

谢谢,艾普斯巴克,奥斯瓦尔多医生和肯特。

相关问题