\ r和\n有什么区别?

Sam*_*Lee 232 line-endings special-characters

怎么样\r\n不同?我认为这与Unix与Windows与Mac有关,但我不确定它们是如何不同的,以及在正则表达式中搜索/匹配的方式.

Jon*_*eet 368

他们是不同的角色.\r是回车,\n是换行.

在"旧"打印机上,\r将打印头送回到行的开头,然后\n将纸张前进一行.因此,两者都必须在下一行开始打印.

显然,现在有些不相关,虽然取决于控制台,您仍然可以使用\r移动到行的开头并覆盖现有文本.

更重要的是,Unix倾向于\n用作行分隔符; 视窗倾向于使用\r\n作为行分隔和Mac(最多OS 9)用于使用\r作为行分隔符.(Mac OS X是Unix-y,所以\n改为使用;但是可能会出现一些兼容性情况\r.)

有关更多信息,请参阅Wikipedia换行文章.

编辑:这是语言敏感的.例如,在C#和Java中,\n 始终表示Unicode U + 000A,它被定义为换行符.在C和C++中,水有点混浊,因为其含义是特定于平台的.请参阅评论了解详情

  • 老人的另一个+1.您仍然可以在Windows命令提示符下按Ctrl + G,按Enter键,然后PC扬声器将发出哔声.那是古代遗留下来的. (35认同)
  • 给老人+1.终端输出用于直接控制美化电子终端(在那些花哨的CRT显示器之前你的TTY).因此,我们得到了回车和换行符中的精彩文物(这些都可能需要,如Jon Skeet所提到的)和诸如"铃"之类的东西,\ b"退格"(不要与"删除"混淆) "),以及与tty通信所需的所有其他控制字符. (22认同)
  • @Wallacoloo:在Widnows 7中我得到了相同的错误,但有BEEP ;-) (8认同)
  • `\n` 不一定是 ASCII 换行符。这是 C 和 C++ 约定,用于在文本模式下执行 I/O 时引用主机平台的行分隔符。大多数实现碰巧使用 ASCII 换行符来表示“\n”,但我认为 C 或 C++ 标准实际上并不要求这样做。如果你想要换行,可以使用“\n”。如果您想要换行,请使用“\x0A”。相比之下,无论实现如何,`\r` _is_ 应该是 ASCII 回车符。 (2认同)
  • @AdrianMcCarthy:当然这个问题实际上并没有*在这里指定*C或C++.在C#中,例如`\n`**保证是换行符(第2.4.4.4节).当然,如果OP已经指定了平台,那将是很好的...此外,我认为这个细节水平会比仅仅提出差异的人更有用而不是有用. (2认同)
  • @AdrianMcCarthy:但至少在C#和Java中,*是*换行.它是U + 000A,由Unicode命名为"LINE FEED"(和NEW LINE).我将编辑提及C和C++的特殊情况,但我真的相信那些*是*特殊情况,而不是相反. (2认同)

Adr*_*thy 90

在C和C++中,\n是一个概念,\r是一个角色,并且\r\n(几乎总是)是一个可移植性的bug.

想想一个旧的电传打字机.打印头位于某些线上和某些列中.将可打印字符发送到电传打字机时,它会在当前位置打印字符并将打印头移动到下一列.(这在概念上与打字机相同,除了打字机通常相对于打印头移动纸张.)

当您想要完成当前行并从下一行开始时,您必须执行两个单独的步骤:

  1. 然后将打印头移回到行的开头
  2. 把它移到下一行.

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.
  • 使用在NL上标准化的EBCDIC的旧IBM系统- 在ASCII字符集中甚至不存在的字符.在Unicode中,NL是U+0085 NEXT LINE,但实际的EBCDIC值是0x15.

为什么不同的系统选择不同的方法?仅仅因为没有通用标准.你的键盘可能会显示"Enter",旧的键盘用来表示"返回",这是Carriage 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?CR?如果?NL?别的什么?便携性如此之多.

C有两种I/O模式:二进制和文本.在二进制模式下,无论发送什么数据都按原样传输.但是在文本模式下,有一个运行时转换,可以将特殊字符转换为主机平台对新行所需的任何内容(反之亦然).

太好了,那么这个特殊的角色是什么?

那么,这也是依赖于实现的,但是有一种与实现无关的方式来指定它:\n.它通常被称为"换行符".

这是一个微妙但重要的一点: \n编译时映射到实现定义的字符值,然后(在文本模式下)在运行时再次映射到底层平台移动所需的实际字符(或字符序列)到下一行.

\n与所有其他反斜杠文字不同,因为涉及两个映射.这种两步映射\n与偶数的显着不同\r,这只是CR的编译时映射(或者底层字符集中最相似的控制代码).

这让许多C和C++程序员兴奋不已.如果您要对其中的100个进行轮询,那么至少99个会告诉您这\n意味着换行.这不完全正确.大多数(可能是全部)C和C++实现使用LF作为神奇的中间值\n,但这是一个实现细节.编译器使用不同的值是可行的.实际上,如果主机字符集不是ASCII的超集(例如,如果它是EBCDIC),那么\n几乎肯定不会是LF.

所以,在C和C++中:

  • \r 实际上是一个回车.
  • \n是一个神奇的值,它在运行时转换(在文本模式下)到主机平台的换行语义.
  • \r\n几乎总是一个可移植性的bug.在文本模式下,这会被转换为CR,然后是平台的换行序列 - 可能不是预期的.在二进制模式下,这会转换为CR,然后是一些可能不是 LF的魔术值- 可能不是预期的.
  • \x0A是表示ASCII LF的最便携方式,但您只想在二进制模式下执行此操作.大多数文本模式实现都会像那样对待\n.


NoM*_*ots 11

  • "\ r"=>返回
  • "\n"=>换行符或换行符(语义)

  • 基于Unix的系统只使用"\n"来结束一行文本.

  • Dos使用"\ r \n"结束一行文本.
  • 其他一些机器只使用"\ r".(Commodore,Apple II,OS OS之前的Mac OS等)


Jos*_*ved 5

简而言之,\r 的 ASCII 值是 13 (CR),\n 的 ASCII 值是 10 (LF)。Mac 使用 CR 作为行分隔符(至少以前是这样,我不确定是否适用于现代 Mac),*nix 使用 LF,Windows 两者都使用(CRLF)。


小智 5

\r 用于指向一行的开头并且可以从那里替换文本,例如

main()
{
printf("\nab");
printf("\bsi");
printf("\rha");
}
Run Code Online (Sandbox Code Playgroud)

产生这个输出:

hai
Run Code Online (Sandbox Code Playgroud)

\n 是为新线。