"\n"和"\r"的区别是什么?

801

回车符 \r 和换行符 \n 在IT技术中有什么区别?

具体而言,\r\n之间是否存在任何实际差异?是否有应使用其中一个而不是另一个的情况?


4
所有答案都很可预知,但我很想知道 \n 和 \r 之间是否存在任何实际上的区别。有没有应该使用其中一种而不是另一种的情况? - Vlad the Impala
14
是的,只包含LF(换行符)的文本文件在某些Windows应用程序中不会被视为已终止,而以CRLF结尾的文本文件在某些Linux应用程序中打开时会出现额外的字符。 - pavium
4
是的,一些 Linux 终端应用程序使用 \r 来进行旋转行动画。 - Murali
10
\r 是否仍然是Mac的普通行末符?我确信在“Classic” Mac系统中是这样,但我曾认为OS X已经类Unix化了。(这说明我对Mac并不熟悉,是吧?) - John Y
19
从历史上看,\n 用于将打印位置下移一行,而 \r 用于将打印位置移回页面的左侧。 - karthik gorijavolu
12个回答

1035

就 ASCII 码而言,它是 3——因为它们分别是 10 和 13;-)。

但说真的,有很多:

  • 在Unix和所有类Unix系统中,\n是行末的代码,\r没有特殊含义
  • 因此,在C和大多数以某种方式复制它的语言中(即使是远程的),\n是行末的标准转义序列(根据需要转换为/从特定于操作系统的序列)
  • 在旧的Mac系统(OS X之前),\r是行末的代码
  • 在Windows(和许多旧操作系统)中,行末的代码是2个字符:\r\n,按照这个顺序
  • 作为一个(令人惊讶的;-)结果(回溯到比Windows旧得多的操作系统),\r\n是Internet上文本格式的标准行终止符
  • 对于电机打字机式的“终端”,\r命令马车向左移动直到碰到最左边的停止位(一个缓慢的操作),\n命令滚轮向上滚动一行(一个更快的操作)-- 这就是为什么你总是有\r\n之前,这样滚轮可以在马车仍然向左移动时移动!-) 维基百科有更详细的解释
  • 对于字符模式终端(通常模拟甚至更老的打印机),在原始模式下,\r\n的作用类似(除了光标之外,因为那里没有马车或滚轮;-)

实际上,在现代文本文件写入的情况下,你应该始终使用\n(如果你在奇怪的操作系统上,比如Windows,底层运行时将进行翻译)。唯一需要使用\r的原因是,如果你要写入字符终端(或更可能是模拟它的“控制台窗口”),并且想要下一行你写的内容覆盖刚刚写的上一行(有时用于幼稚的“ASCII动画”效果,例如进度条)-虽然在GUI的世界里这已经过时了;-)。


17
补充此回答的历史记录:随着行速度从每秒10个字符增加,需要超过2个字符的时间使打印头回到起始位置,并且通常会在\n之后添加额外的无害字符(通常为NUL即\0),以便多余的时间。操作系统会透明地处理这个过程,因此您在遗留代码中找不到任何痕迹。 - Mark Ransom
12
Windows为什么被认为是一个“奇怪”的操作系统? - mailmindlin
43
@mailmindlin -- 你问“Windows是一个怎样‘奇怪’的操作系统?”。答案:它有很多种怪异之处(不穿袜子数脚趾头也数不过来)除了 Windows,其它所有活着的操作系统都是基于 Unix 的……Windows 在很多方面都与它们迥然不同。在这个特定的问题中,Windows 是唯一将两个字节(\n\r)视为规范换行符的操作系统……没有任何合理的理由,只是因为古老历史原因,在本线程的其他地方已经解释过了……而其它每个操作系统都使用一个单字符(99%+ 使用`\n')作为换行符。 - Alex Martelli
4
对于所有将来可能编写某种解析器的人,我有一个小建议——永远不要忘记正确处理行末。因为我曾经忘记了\r(我在使用Linux),所以遇到了一些非常糟糕的经历。当我开始解析一份看似有效的文件时,我的解析器失败了,因为我正在解析的文件是在Windows中创建的。:D 在这一切中的主要问题是\n\r都不可见,就像字符a.(等一样。 - rbaleksandar
7
所有其他幸存的操作系统都是基于Unix的,这并不奇怪,考虑到它们都只是Unix的某种变体。这就像说香草口味的冰淇淋很奇怪,因为100个人决定在他们的巧克力冰淇淋上撒上100种不同的配料,从而创造出100种不同的口味。我真的厌倦了人们将Windows和Unix进行比较,好像它们应该是彼此的替代品。这就像将跑车与拖拉机进行比较,因为它们都是机动车辆。然后声称其中一种比另一种更好,这根本没有意义。 - J. Doe
显示剩余5条评论

189

在历史上,\n 用于向下移动打印机的打印头,而 \r 则用于将打印头移回到页面的左侧。


26
或许这并不是一个针对计算机问题非常实用的答案,但这则历史小知识无论如何都会收到我的点赞。 - John Y
2
想象一下 \r 就像你把物理打字机的打字部分向左推,也就是回车。 - Jo Smo
3
不是移动打印机的打印头,而是通过转动滚筒来将纸张向上移动。 - Roddy
12
一切运动都是相对的。这张纸是我的世界,相对于它,马车在向下移动 :P - tster
5
现代系统中,\r仍然可以表示“回车符”。考虑这段C语言代码printf("abcdefghijlm\rNOP\n");在OpenSuSe上使用gcc-8编译并在终端上运行的输出结果为NOPdefghijlm。字符串中的\r(回车符)使光标移动到行首并且\r后面的字符(即“NOP”)覆盖了先前的字符(即“abc”)。你也可以使用退格键(\b)来实现类似的"回车移动"效果,例如printf("abcdefghijlm\b\bNOP\n");将产生abcdefghijNOP的结果。 - GMc
a TLDR version, nice - Kevin Chandra

65

两个不同的字符。

\n 在Unix文本文件中用作行末终止符。

\r (在OS X之前)在Mac文本文件中被用作行末终止符。

\r\n (即同时使用这两个字符)在Windows和DOS文本文件中用于终止行。


2
请注意,有些计算机在按下回车键时使用 \n\r 作为行尾标记,例如Acorn和RISC OS。 - Anders
14
澄清一下:\r 已经不再是 Mac 上的换行符号了很长时间了。自从 2001 年发布基于 Unix 的 Mac OS X 系统之后,现在使用的是 \n - jbbuckley
7
但还有一些应用程序在使用\r,例如:MS Office 2011 Excel:保存一个CSV文件(采用默认设置)- 将保存一个带有\r行结尾的ISO-8859-1编码文件。 - CodeBrauer

37
自从没有人特别提到它(他们年轻得不知道/记得吗?)- 我怀疑使用\r\n起源于打字机和类似的设备。在使用多行功能打字机时,当您想要一个新行时,需要执行两个物理动作:将纸张滑回页面的开头(向左,在美国),并将纸张上移一格。在线打印机时代,例如,做粗体文本的唯一方法是执行一个没有换行符的回车,并在旧字符上打印相同的字符,从而增加更多的墨水,使其看起来更深(加粗)。当打字机的机械“换行”功能失败时,这就是让人讨厌的结果:如果您没有注意,您可以在先前的文本行上键入文字。

4
ASCII标准的换行符是\r\n。(除了贝尔电电话控制标准委员会的短暂时期)。为了获得电话垄断,贝尔电电话放弃了消息业务(电报、电传打字机),并不关心标准的现有使用。HTTP、HTML、PCDOS和MSDOS都使用ASCII标准。贝尔电电话选择在Unix中采用非标准,因为他们没有现有业务需要兼容。 - david

18

不同操作系统使用两种不同的字符。在传输数据时,这也会影响到使用 TCP/IP 的情况,需要使用 \r\n

\n 用于 Unix。

\r 用于 Mac。

\r\n 用于 Windows 和 DOS。


13
我认为你对应用协议有些混淆了,TCP/IP不涉及换行符(\n和\r)。 - jean-loup
9
TCP/IP不要求使用\r\n。基于Telnet的各种协议需要它,包括SMTP、POP3、FTP、HTTP等。 - user207421

16
  • \r回车符 CR —将光标返回到一行的开头
  • \n换行符(新行)LF —向上移动一行纸张

在屏幕输出的情况下:

  • CR:将光标返回到当前行的开头
  • LF:将光标向下移动一行

例如:

Hello,\nworld\r!

应该在您的终端上呈现为:

Hello,
!     world

一些操作系统可能会破坏与预期行为的兼容性,但这并不会改变对“\n和\r之间的区别”这个问题的回答。


14
为了完成任务,您可以在shell(bash)脚本中使用\r将光标发送到行首,并使用\n将光标置于新行。例如,请尝试:

To complete,

echo -en "AA--AA" ; echo -en "BB" ; echo -en "\rBB"
  • 第一个"echo"显示 AA--AA
  • 第二个: AA--AABB
  • 最后一个: BB--AABB

但不要忘记使用-en作为参数。


13

在Windows中,\n会移动到下一行的开头。而\r则是将光标移到当前行的开头,而不会移动到下一行。在我的控制台应用程序中,我会使用\r来测试一些代码并且不想看到文本在屏幕上滚动。例如,当我打印出一些文本(如帧率(FPS))后,我会使用printf("%-10d\r", fps);,这将把光标返回到行的开头,而不向下移动到下一行,并且可以在屏幕上显示其他信息,以便在同一行上更新帧速率同时不会被覆盖。(其中的%-10确保输出至少有10个字符,并且左对齐,所以最终会填充空格,覆盖该行的任何旧值)。这对于像这样的东西非常方便,通常是在我将调试信息输出到我的控制台屏幕时。

一个小历史

/r代表着回车归位,它的历史渊源可以追溯到打字机时代。回车操作会让打字机的滑轨移动到最右边,以便在一行的开头进行打字。

/n代表着换行,同样来自于打字机时代,你需要将滑轨移动到下一行。不过并不一定是移到下一行的开头,这就是为什么一些操作系统需要在\r后面加上一个\n的原因,因为这是打字机进行操作的顺序。这也解释了为什么旧的8位计算机使用Return而不是Enter,因为它更熟悉carriage return


5
换行符(\n)和回车符(\r)有什么区别?特别是,\n\r之间是否存在任何实际差异?有没有应该使用其中一个而不是另一个的情况?
我想对\n代表换行和\r代表回车的转义序列进行一个简单的实验,以说明它们之间的明显差异。
我知道这个问题是独立于编程语言的,但我们至少需要一种编程语言来完成实验。在我的情况下,我选择了C++,但这个实验通常适用于任何编程语言。
程序只是通过for循环迭代来打印一句话到控制台中。

换行程序:

#include <iostream>

int main(void)
{
    for(int i = 0; i < 7; i++)
    {
       std::cout << i + 1  <<".Walkthrough of the for-loop \n";   // Notice `\n` at the end.
    }
    return 0;
}

输出:

1.Walkthrough of the for-loop
2.Walkthrough of the for-loop
3.Walkthrough of the for-loop
4.Walkthrough of the for-loop
5.Walkthrough of the for-loop
6.Walkthrough of the for-loop
7.Walkthrough of the for-loop

请注意,执行此C++代码的任何系统都可能不会提供这个结果。但对于大多数现代系统而言,这个代码应该是有效的。详情请见下方。


现在是同样的程序,只是在打印序列末尾将\n替换为\r

回车符程序:

#include <iostream>

int main(void)
{
    for(int i = 0; i < 7; i++)
    {
       std::cout << i + 1  <<".Walkthrough of the for-loop \r";   // Notice `\r` at the end.
    }
    return 0;
}

输出:

7.Walkthrough of the for-loop 

注意到区别了吗? 区别就在于使用回车转义序列 \r 在每个打印序列的末尾时,下一个迭代不会进入以下文本行-在每个打印序列的末尾,光标没有跳到*下一行的开头。
相反,光标跳回到该行的开头,在使用\r字符之前的末尾所在的行上。 -结果是每个随后的打印序列都将替换前一个打印序列。
*注意: \ n 不一定跳转到以下文本行的开头。在一些通常更老的操作系统上, \ n 换行符的结果可以是它可以跳转到以下任何位置,而不仅仅是开头。这就是为什么它们需要使用 \r \n 以获得下一行文本的开头。
这个实验向我们展示了在打印序列的迭代的上下文中,换行和回车之间的差异。
当讨论程序中的输入时,某些终端/控制台可能会将回车隐式转换为换行,以获得更好的可移植性、兼容性和完整性。
但是,如果您可以选择一种方法来替代另一种方法,或者想要或需要明确地仅使用一种方法,您应始终使用适合其目的并严格区分的方法。

4
仅为增加混淆,我一直在使用HTML页面中的TextArea元素开发一个简单的文本编辑器。由于担心CR/LF兼容性问题,我编写了代码来检查平台,并使用适用于该平台的换行约定。
然而,当通过一个小的JavaScript函数检查TextArea实际包含的字符时,我发现了一些有趣的事情。
对于测试,我输入了以下文本:
Hello, World[回车]
Goodbye, Cruel World[回车]
当我检查文本数据时,我获得的字节序列是这样的:
48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 0a 47 6f 6f 64 62 79 65 2c 20 43 72 75 65 6c 20 57 6f 72 6c 64 0a
现在,大多数人看到这个输出,看到0a但没有0d字节,会认为这个输出是在Unix/Linux平台上获得的。但是,这个序列是我在Windows 7 64位上的Google Chrome中获得的。
因此,如果您正在使用TextArea元素并检查文本,请像我上面所做的那样检查输出,以确保从您的TextArea返回了哪些实际字符字节。我还没有看到这是否在其他平台或其他浏览器上有所不同,但如果您正在通过JavaScript执行文本处理,并且需要使该文本处理与平台无关,请记住这一点。
上面的帖子中涵盖的约定适用于控制台输出,但是HTML元素似乎遵循UNIX/Linux约定。除非有人在不同的平台/浏览器上发现了其他情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接