^M vs \n in vim 字符串替换

^M vs \n in vim string replacement

在进行字符串替换 (:s/x/y/) 时,Vim 对待 ^M 的方式似乎存在某种不对称性。

也许举个例子最好;假设我们有这个文本文件:

foo:bar:biz

我想把它分成几行。这很好用:

:s/:/^M/g

(注意 ^M 是通过键入 Ctrl-VEnter 产生的)

文本文件中的结果:

foo
bar
baz

现在,如果我撤消它并重试,我注意到这有效:

:s/:/\n/g

这里,生成的文本是:

foo^@bar^@biz

也就是说,它们是由ASCIINUL字节(0x00)连接起来的。

问题1:为什么在替换中使用\n会导致NUL字节?

现在,我估计 "okay, I guess ^M is used as the 'line separator' character in some way, for Vim; I can work with that"。

所以我做了另一个实验,从每行一个项目的文本文件开始:

foo
bar
baz

现在,我想用冒号加入它们,所以它看起来像上面的第一个化身。

所以我运行:

:%s/^M/:/

但这失败了,错误是:

E486: Pattern not found: ^M

但是,这个命令确实有效:

:%s/\n/:/

生产:

foo:bar:biz:

(我可以自己去掉尾随的冒号)

那么问题 2:为什么 \n 在这种情况下有效,而 ^M 却无效?

最终,问题 3:为什么 \n^M 之间存在这种不对称,具体取决于它是在右手还是左手字符串替换命令的一侧?

搜索时,\n 是一个 "catch-all" 原子,可以方便地匹配任何一种 "end-of-line":CRLFCRLF.

替换时,\n<Nul>,表示为^@

替换时,\r是当前fileformat的合法"end-of-line"。

总之,习惯这种模式,然后继续:

:s/\n/\r

参见 :help NL-used-for-NulCR-used-for-NL