在 Vim 的搜索/替换语法中标准化 \n 和 \r

在 Vim 的搜索/替换语法中标准化 \n 和 \r

在 Vim 中,搜索对于换行符,请将其输入为\n,但替换字符串中的换行符必须输入为\r。我理解这种行为的原因,但就我的目的而言,我发现这很烦人。我希望能够\n在搜索模式和替换字符串中使用 来表示(本质上)相同的意思:具体来说,在搜索模式中它应该匹配换行符,而在替换字符串中它应该插入换行符。

有没有办法实现这种行为?我认为简单的重新映射不会起作用,因为需要解析替换命令才能确定它\n是搜索模式的一部分还是替换字符串。

答案1

您必须连接到命令行;无论是通过 执行时<CR>,还是在输入 时立即执行\n。使用:help c_CTRL-\_e,您可以评估函数并修改命令行。这是一个您可以在此基础上进行构建和改进的演示(现在对替换的检查非常简单):

cnoremap n <C-\>eTranslateBackslashN()<CR>
function! TranslateBackslashN()
    if getcmdtype() ==# ':' && getcmdline() =~# 's/.*/.*\\$' " Improve this!
        return getcmdline() . 'r'
    endif
    return getcmdline() . 'n'
endfunction

答案2

正如 Ingo Karkat 所写,可以使用 找到解决方案c_CTRL-\_e。这是我使用的版本,除了正则表达式模式外,它与原始解决方案相同。(因为这实际上只是 Ingo Karkat 的答案,略有改进由 Ingo Karkat 建议,我不认为它实际上值得有自己的答案,但我想我被否决了:http://chat.stackexchange.com/transcript/message/15021397#15021397

function! TranslateBackslashN()
    if getcmdtype() ==# ':' && getcmdline() =~#
      \ '[%>]s\([um]\w*\)\?\(.\).\{-}\(\\\)\@<!\2.*\\$'
        return getcmdline() . 'r'
    endif
    return getcmdline() . 'n'
endfunction
cnoremap n <C-\>eTranslateBackslashN()<CR>

正则表达式模式的解释:

  • [%>]s确保替换仅s在范围之后立即发生
  • \([um]\w*\)\?匹配s命令的变体,例如smagic
  • \(.\)将是第一个非单词字符,因为所有单词字符都已被\w可选组所吃掉。请注意,这是组2。这是分隔符,通常为/。请注意_,是单词字符,也是有效分隔符,因此如果以_这种方式使用,模式将无法正常工作。_不过,我从来没有用过 用作分隔符,所以我不会担心它。同样,有些字符不是单词字符,但不应该用作分隔符,但我在这里并不担心,因为在那种情况下命令无论如何都会失败。我想\W在这里使用,但由于某种原因,我在测试它时它没有起作用。
  • .\{-}应该匹配模式(\{-}就像 Perl 的一样*?)。
  • \(\\\)\@<!\2匹配下一个前面没有反斜杠的分隔符。Perl 中的等价字符是(?<!\\)\2
  • .*匹配迄今为止替换字符串中的所有内容。
  • \\$仅当目前的命令以反斜杠结尾时才匹配。

答案3

使用插件的替代答案(这是我决定使用的解决方案,尽管它仅适用于 Vim 7.4+):

使用魔法活力,放入let g:VeryMagicSubstituteNormalise = 1你的.vimrc

(此插件使用CR调度器插件,允许在命令中进行文本替换已按下 Enter 键,但命令实际上已执行。因此不需要重新映射\n,并且替换对用户是不可见的,使得\n在两个上下文中看起来具有相同的“含义”。

相关内容