\n
是换行符,\r
是回车符(^M
),但是当替换\r
是换行符而\n
是空字节(^@
)时。这的起源是什么不对称?鉴于这种行为是...至少可以说是怪异的(当您第一次遇到错误时,它适得其反)我希望有一些奇怪的历史原因。
(顺便说一句,有什么方法可以“修复”此行为并获得更直观的提示?)
#1 楼
在最基本的层次上,:substitute
的搜索和替换部分之间已经存在不对称性,因为前者是正则表达式,后者是文本,并带有特定的附加转义序列。您对\n
的含义的直觉只是突出了这一点。例如,请考虑搜索中的\n
与文字\n
不匹配。它匹配行尾(EOL)字节序列,根据缓冲区的\r
可能是\r\n
,\n
或仅仅是'fileformat'
。为什么
\r
用来表示“插入EOL”,其背后的一些历史。 Vi无法处理文件中的NUL字节。 Vim改进了这一点,通过在内部用NL字节替换NUL字节(因为C字符串是NUL分隔的)。由于替换中的
:substitute
只是插入到该行的内部表示中,因此该实现细节泄漏到\n
的行为中。 ,用于指示NUL字节。 \r
插入一个EOL,将内部行一分为二。 Vim实际上并不将EOL字节存储在内存中,而是在读取/写入缓冲区时对它们进行反序列化。在不破坏许多脚本和许多用户的肌肉内存的情况下,现在无法对其进行更改。幸运的是,它记录在
:help sub-replace-special
中。#2 楼
NUL
字节是C中的字符串终止符,因此,Vim使用此约定,如:h NL-used-for-Nul
手册中所述:文件中的该约定已扩展到
:s/.../.../
命令,而不是substitute()
函数。 \r
调用中替换字符串中的\n
和substitute()
保留了其原始含义。我认为这两种行为都不存在更深层次的原因。 Vim只是从原始
vi
进行了有机演变。从来没有什么大的蓝图,功能只是相互叠放在一起,而只需花费很少的精力就可以使它们井井有条。#3 楼
其他Vi克隆不支持替换\r
或\n
(作为真实的反斜杠和字母),但是真实的^M
(CTRL-V Enter)的行为是将行分为两行是标准行为:在repl中输入
在Unix History档案中,它出现的BSD ex / vi的第一个版本是4.1cBSD(
@(#)ex_re.c 7.2 10/16/81
,并且在4BSD(@(#)ex_re.c 6.2 10/23/80
)[存档中不存在4.1a和4.1b]。相关代码为:
/* ^V <return> from vi to split lines */
if (c == '\r')
c = '\n';
这是新闻文件中也提到过:
现在可以通过在rhs中使用^ V
以前在ex命令模式下受支持的行为是反斜杠输入(即反斜杠后跟真实的换行符)来插入换行符。
#4 楼
不对称性的起源可以追溯到计算历史中。简短版本:
<CR> & <LF> (Carriage-Return and Linefeed)
==
\r & \n
长版本:
第一个屏幕基本上是电传打字机(TTY)的数字版本,并使用了控制代码以生成与打印机类似的行为。回车将光标(或打印头)移至开始列。换行前进到下一行(在屏幕上),并将纸张向前一行送进。
对于打印机,必须配对使用
<CR><LF>
,否则输出将看起来不正确。在早期的屏幕上,该问题仍然成立。DOS(和之后的sorta-Windows)遵循旧的标准,并使用
<CRLF>
保存文本。 * NIX文本(大多数vi用户熟悉)仅使用
<LF>
来提高效率。要在Windows中进行测试,请使用Word / Wordpad并保存几行文本“类型:文本-MS-DOS格式”。然后在记事本中打开相同的文件。它看起来应该很正常。然后在Word /写字板中将相同的文件“作为类型:文本”保存。记事本将忽略所有换行符并一起运行这些行。 [记事本的文本格式默认为
\r\n
组合,而Word / Wordpad的默认格式为\n
。] \ r是
<CR>
的等效代码\ n是
<LF>
的等效代码根据我对vi的经验(非常有限),它将尝试从DOS文本编辑器中“修复”
<CRLF>
组合。 vi最终删除了一个字符,并替换为<NUL>
。我停止使用vi的很大一部分原因。
评论
尽管您所有的信息都很有趣,但是它仅说明了为什么\ r是
– Tumbler41
16年8月29日在19:52
谢谢! :-)当您回复时,我正在更改它。 (在最后一段中添加。)
–罗宾
16年8月29日在19:57