有\r
什么\n
不同?我认为这与 Unix、Windows 和 Mac 有关,但我不确定它们到底有什么不同,以及在正则表达式中搜索/匹配的内容。
9 回答
他们是不同的角色。\r
是回车,\n
是换行。
在“旧”打印机上,\r
将打印头送回行首,并将\n
纸张前进一行。因此,两者都需要在下一行开始打印。
显然,现在这有点无关紧要,尽管取决于控制台,您仍然可以使用\r
它移动到行首并覆盖现有文本。
更重要的是,Unix 倾向于\n
用作行分隔符;Windows 倾向于\r\n
用作行分隔符,而 Mac(直到 OS 9)通常用作行\r
分隔符。(Mac OS X 是 Unix-y,所以\n
改用它;但可能有一些兼容性情况\r
需要改用。)
有关详细信息,请参阅Wikipedia 换行文章。
编辑:这是语言敏感的。例如,在 C# 和 Java 中,\n
总是表示 Unicode U+000A,它被定义为换行符。在 C 和 C++ 中,水有点混浊,因为含义是特定于平台的。详情见评论。
在 C 和 C++ 中,\n
是一个概念,\r
是一个字符,并且\r\n
(几乎总是)是一个可移植性错误。
想想旧的电传打字机。打印头位于某行某列中。当您将可打印字符发送到电传打字机时,它会在当前位置打印字符并将头部移动到下一列。(这在概念上与打字机相同,只是打字机通常相对于打印头移动纸张。)
当您想完成当前行并从下一行开始时,您必须执行两个单独的步骤:
- 将打印头移回行首,然后
- 将其移至下一行。
ASCII 将这些动作编码为两个不同的控制字符:
\x0D
(CR) 将打印头移回行首。(Unicode 将其编码为U+000D CARRIAGE RETURN
。)\x0A
(LF) 将打印头向下移动到下一行。(Unicode 将其编码为U+000A LINE FEED
。)
在电传打字机和早期技术打印机时代,人们实际上利用了这是两个独立的操作这一事实。通过发送 CR 而不跟随 LF,您可以在已打印的行上打印。这允许使用重音、粗体和下划线等效果。一些系统会多次叠印以防止密码在硬拷贝中可见。在早期的串行 CRT 终端上,CR 是控制光标位置以更新屏幕上已有文本的方法之一。
但大多数时候,你实际上只是想跳到下一行。一些系统不需要一对控制字符,而是只允许一个或另一个。例如:
- Unix 变体(包括 Mac 的现代版本)仅使用 LF 字符来表示换行符。
- 旧的(OSX 之前的)Macintosh 文件仅使用 CR 字符来表示换行符。
- VMS、CP/M、DOS、Windows 和许多网络协议仍然期望两者:CR LF。
- 使用EBCDIC的旧 IBM 系统在 NL 上进行了标准化——一个在 ASCII 字符集中甚至不存在的字符。在 Unicode 中,NL 为
U+0085 NEXT LINE
,但实际的 EBCDIC 值为0x15
。
为什么不同的系统选择不同的方法?仅仅是因为没有通用的标准。你的键盘可能会说“Enter”,旧键盘曾经说“Return”,这是回车的缩写。事实上,在串行终端上,按 Return 实际上会发送 CR 字符。如果您正在编写文本编辑器,则很容易使用从终端输入的字符。也许这就是为什么较旧的 Mac 只使用 CR。
现在我们有了标准,就有更多的方式来表示换行符。尽管在野外极为罕见,但 Unicode 具有以下新字符:
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR
甚至在 Unicode 出现之前,程序员就想要用简单的方法来表示一些最有用的控制代码,而不必担心底层字符集。C 有几个用于表示控制代码的转义序列:
\a
(警告)敲响电传打字机铃或使终端发出哔哔声\f
(换页)移动到下一页的开头\t
(用于制表符)将打印头移动到下一个水平制表符位置
(此列表故意不完整。)
这种映射发生在编译时——编译器看到\a
并放置任何用于敲钟的魔法值。
请注意,这些助记符中的大多数都与 ASCII 控制代码直接相关。例如,\a
将映射到0x07 BEL
. 可以为使用非 ASCII 字符集(例如 EBCDIC)的系统编写编译器。大多数具有特定助记符的控制码都可以映射到其他字符集中的控制码。
嘘!可移植性!
嗯,差不多。在 C 语言中,我可以写下printf("\aHello, World!");
哪个响铃(或哔哔声)并输出一条消息。但是如果我想在下一行打印一些东西,我仍然需要知道主机平台需要什么才能移动到下一行输出。CR LF?铬?如果?荷兰?还有什么?便携性就这么多。
C 有两种 I/O 模式:二进制和文本。在二进制模式下,发送的任何数据都会按原样传输。但是在文本模式下,有一个运行时翻译可以将特殊字符转换为主机平台需要的新行(反之亦然)。
太好了,那么特殊字符是什么?
好吧,这也是依赖于实现的,但是有一种独立于实现的方式来指定它:\n
. 它通常被称为“换行符”。
这是一个微妙但重要的一点:在 编译时\n
映射到实现定义的字符值(在文本模式下),然后在运行时再次映射到底层平台移动所需的实际字符(或字符序列)到下一行。
\n
与所有其他反斜杠文字不同,因为涉及两个映射。这种两步映射\n
与 even 明显不同\r
,后者只是到 CR 的编译时映射(或任何底层字符集中最相似的控制代码)。
这让许多 C 和 C++ 程序员感到困惑。如果您要对其中的 100 个进行投票,至少有 99 个会告诉您这\n
意味着换行。这并不完全正确。大多数(也许是全部)C 和 C++ 实现使用 LF 作为 的神奇中间值\n
,但这是一个实现细节。编译器可以使用不同的值。事实上,如果主机字符集不是 ASCII 的超集(例如,如果它是 EBCDIC),那么\n
几乎肯定不会是 LF。
因此,在 C 和 C++ 中:
\r
字面意思是回车。\n
是一个神奇的值,在运行时(以文本模式)被翻译到/从主机平台的换行语义。\r\n
几乎总是一个可移植性错误。在文本模式下,这将被翻译为 CR,然后是平台的换行符序列——可能不是预期的。在二进制模式下,这将被转换为 CR,然后是一些可能不是LF 的魔法值——可能不是预期的值。\x0A
是表示 ASCII LF 的最便携方式,但您只想在二进制模式下执行此操作。大多数文本模式实现都会将其视为\n
.
- "\r" => 返回
"\n" => 换行或换行(语义)
基于 Unix 的系统只使用“\n”来结束一行文本。
- Dos 使用“\r\n”结束一行文本。
- 其他一些机器只使用“\r”。(Commodore、Apple II、OS X 之前的 Mac OS 等。)
\r
用于指向一行的开头并可以从那里替换文本,例如
main()
{
printf("\nab");
printf("\bsi");
printf("\rha");
}
产生这个输出:
hai
\n
用于新行。
简而言之,\r 的 ASCII 值为 13(CR),\n 的 ASCII 值为 10(LF)。Mac 使用 CR 作为行分隔符(至少,它以前是这样,我不确定现代 Mac 是否如此),*nix 使用 LF,而 Windows 两者都使用(CRLF)。
\r 是回车;\n 是换行(换行)...取决于操作系统的每个含义。阅读这篇文章,了解更多关于 C 中 '\n' 和 '\r\n' ... 之间的区别。
除了@Jon Skeet 的回答:
传统上,Windows 使用 \r\n、Unix \n 和 Mac \r,但是较新的 Mac 使用 \n,因为它们是基于 unix 的。
在 C# 中,我发现他们在字符串中使用 \r\n 。
\r 用于回车。(ASCII 值为 13) \n 用于换行。(ASCII 值为 10)