我们都知道,在搜索时\n
是换行符,并且\r
是回车符(^M
),但是当替换\r
是换行符时\n
则是空字节(^@
)。
这种不对称的根源是什么?鉴于这种行为是……至少可以说是怪异的(当您第一次出错时,它适得其反)我希望这是有一些奇怪的历史原因。
(顺便说一下,是否有某种方法可以“修复”此行为并获得更直观的效果?)
我们都知道,在搜索时\n
是换行符,并且\r
是回车符(^M
),但是当替换\r
是换行符时\n
则是空字节(^@
)。
这种不对称的根源是什么?鉴于这种行为是……至少可以说是怪异的(当您第一次出错时,它适得其反)我希望这是有一些奇怪的历史原因。
(顺便说一下,是否有某种方法可以“修复”此行为并获得更直观的效果?)
Answers:
在最基本的层次上,搜索和替换部分之间已经存在不对称性,: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
。
甲NUL
字节是在C语言的字符串终止子,并且由于这个原因Vim使用该约定,在手册中所描述:h NL-used-for-Nul
:
文件中的<Nul>字符作为<NL>存储在内存中。在显示屏中,它们显示为“ ^ @”。读写文件时完成翻译。要将<Nul>与搜索模式匹配,您只需输入CTRL- @或“ CTRL-V 000”。这可能正是您所期望的。内部字符在搜索模式中被替换为<NL>。与众不同的是,键入CTRL-V CTRL-J还会插入<NL>,因此也会在文件中搜索<Nul>。{Vi根本无法处理文件中的<Nul>个字符}
该约定已溢出到:s/.../.../
命令,但没有溢出到substitute()
函数。 \r
和\n
替换字符串中substitute()
的呼叫保持其原有的意义。
我认为这两种行为都没有更深层次的原因。Vim只是从原始版本有机地演变而来vi
。从来没有什么大的蓝图,功能只是相互叠加,而很少花费精力使它们井井有条。
其他Vi克隆不支持\r
或\n
替代(以真实的反斜杠和字母表示),但是real ^M
(CTRL-V Enter)的行为是将行为分为两行,这是标准行为:
在repl中输入<carriage-return> (在ex模式下需要转义<backslash>,在open或vi模式下需要转义<control> -V )应在该点分割行,在编辑缓冲区中创建新行。<carriage-return>应该被丢弃。
在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 <return>来用vi中的替换命令分割行。这照顾了使用ex命令模式的最后一个很好的理由。
以前在ex命令模式下支持的行为是反斜杠输入(即反斜杠后跟真实的换行符)以插入换行符。
不对称性的起源可以追溯到计算历史中。
精简版:
<CR> & <LF> (Carriage-Return and Linefeed)
==
\r & \n
较长的版本:
第一个屏幕基本上是电传打字机(TTY)的数字版本,并使用控制代码来产生与打印机相似的行为。回车将光标(或打印头)移至开始列。换行前进到下一行(在屏幕上),并将纸张向前一行送进。
对于打印机,您必须进行配对,<CR><LF>
否则输出将看起来不正确。在早期的屏幕上,问题仍然存在。
DOS(和之后的sorta-Windows)遵循旧标准,并使用保存文本<CRLF>
。
* NIX文本(大多数vi用户熟悉)仅<LF>
用于提高效率。
要在Windows中进行测试,请使用Word / Wordpad并保存几行文本“作为类型:文本-MS-DOS格式”。然后在记事本中打开相同的文件。它看起来应该很正常。然后在Word / Wordpad中将“类型”保存为相同的文件:“文本”。记事本将忽略所有换行符并一起运行这些行。[记事本的文本格式默认为\r\n
组合,而Word / Wordpad默认为\n
。]
\ r是等效的代码 <CR>
\ n等于 <LF>
根据我(非常有限的)使用vi的经验,它将尝试<CRLF>
从DOS文本编辑器中“修复”该组合。vi最后删除了一个字符,替换为<NUL>
。我停止使用vi的很大一部分原因。
\r
是<CR>
和\n
是<LF>
。它没有解决实际的问题,即为什么在不同的上下文中\n\r
表现不同。