r和n有什么不同?我认为这与Unix、Windows和Mac有关,但我不确定它们到底有什么不同,以及在正则表达式中搜索/匹配哪个。


当前回答

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

其他回答

他们是不同的角色。\r是换行,\n是换行。

在“老式”打印机上,r将打印头送回行首,n将纸张向前移动一行。因此,要开始下一行的打印,两者都是必要的。

显然,现在这有点无关紧要,尽管取决于控制台,您仍然可以使用\r移动到行开始并覆盖现有的文本。

更重要的是,Unix倾向于使用\n作为行分隔符;Windows倾向于使用\r\n作为行分隔符,而mac(直到OS 9)则使用\r作为行分隔符。(Mac OS X是Unix-y,所以使用\n代替;不过,在一些兼容的情况下,可能会使用\r代替。)

有关更多信息,请参阅维基百科换行文章。

编辑:这是语言敏感的。例如,在c#和Java中,\n总是表示Unicode U+000A,它被定义为换行。在C和c++中,水有些浑浊,因为其含义是特定于平台的。详见评论。

除了@Jon Skeet的回答:

传统的Windows使用\r\n, Unix \n和Mac \r,但是新的Mac使用\n,因为它们是基于Unix的。

在C和c++中,\n是一个概念,\r是一个字符,\r\n(几乎总是)是一个可移植性错误。

想想老式的电传打字机。打印头位于某一行和某列上。当您向电传打字机发送一个可打印字符时,电传打字机在当前位置打印该字符,并将字符头移到下一列。(这在概念上与打字机是一样的,除了打字机通常会相对于打印头移动纸张。)

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

然后,将打印头移回行首 移动到下一行。

ASCII将这些操作编码为两个不同的控制字符:

\x0D (CR)将打印头移回行首。(Unicode将其编码为U+000D回车。) \x0A (LF)将打印头向下移动到下一行。(Unicode编码为U+000A换行。)

In the days of teletypes and early technology printers, people actually took advantage of the fact that these were two separate operations. By sending a CR without following it by a LF, you could print over the line you already printed. This allowed effects like accents, bold type, and underlining. Some systems overprinted several times to prevent passwords from being visible in hardcopy. On early serial CRT terminals, CR was one of the ways to control the cursor position in order to update text already on the screen.

但大多数时候,你只是想看下一行。有些系统不需要这对控制字符,只允许其中之一。例如:

Unix变体(包括现代版本的Mac)只使用LF字符来表示换行符。 旧的(osx之前)Macintosh文件只使用CR字符来表示换行符。 VMS、CP/M、DOS、Windows和许多网络协议仍然需要两者:CR LF。 旧的IBM系统使用在NL上标准化的EBCDIC——NL是ASCII字符集中甚至不存在的字符。在Unicode中,NL是U+0085 NEXT LINE,但实际的EBCDIC值是0x15。

为什么不同的系统选择了不同的方法?很简单,因为没有统一的标准。你的键盘上可能显示的是“Enter”,而旧的键盘上显示的是“Return”,这是回车的缩写。事实上,在串行终端上,按回车键实际上是发送CR字符。如果您正在编写一个文本编辑器,那么很容易使用从终端输入的字符。也许这就是为什么老的mac电脑只使用CR。

既然我们有了标准,就有了更多表示换行符的方法。虽然在现实中非常罕见,但Unicode有了像这样的新字符:

U+2028行分隔符 U+2029分段分离器

甚至在Unicode出现之前,程序员就希望用简单的方法来表示一些最有用的控制代码,而不用担心底层字符集。C有几个转义序列来表示控制代码:

\a(表示警报),发出电传打字铃或使终端机发出哔哔声 \f(用于表单提要),它会移动到下一页的开头 \t(对于制表符),它将打印头移动到下一个水平制表符位置

(本列表有意不完整。)

这种映射发生在编译时——编译器看到\a,然后放入任何用来敲钟的神奇值。

请注意,这些助记符大多数都与ASCII控制码直接相关。例如,\a将映射到0x07 BEL。编译器可以为一个系统编写,它使用的主机字符集不是ASCII(例如,EBCDIC)。大多数具有特定助记符的控件代码可以映射到其他字符集中的控件代码。

万岁!可移植性。

嗯,差不多。在C语言中,我可以写printf("\aHello, World!");按铃(或哔哔声)并输出消息。但是如果我想在下一行打印一些东西,我仍然需要知道主机平台需要什么来移动到下一行输出。CR低频?CR吗?低频?问吗?别的吗?这就是便携性。

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

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

好吧,这也是依赖于实现的,但是有一种与实现无关的方式来指定它:\n。它通常被称为“换行符”。

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

\n不同于所有其他反斜杠字面量,因为涉及到两个映射。这种两步映射使得\n与\r明显不同,\r只是到CR(或底层字符集中最相似的控制代码)的编译时映射。

这让许多C和c++程序员感到困惑。如果你要调查其中的100个,至少有99个会告诉你\n意味着换行。这并不完全正确。大多数(也许是所有)C和c++实现使用LF作为\n的神奇中间值,但这是实现细节。对于编译器来说,使用不同的值是可行的。事实上,如果主机字符集不是ASCII的超集(例如,如果它是EBCDIC),那么\n几乎肯定不是LF。

因此,在C和c++中:

\r is literally a carriage return. \n is a magic value that gets translated (in text mode) at run-time to/from the host platform's newline semantics. \r\n is almost always a portability bug. In text mode, this gets translated to CR followed by the platform's newline sequence--probably not what's intended. In binary mode, this gets translated to CR followed by some magic value that might not be LF--possibly not what's intended. \x0A is the most portable way to indicate an ASCII LF, but you only want to do that in binary mode. Most text-mode implementations will treat that like \n.

\r是回车;\n是换行(换行)…这取决于操作系统。阅读这篇文章,了解更多关于“\n”和“\r\n”的区别…在C。

\r是用来指向一行的开始,可以替换从那里开始的文本。

main()
{
printf("\nab");
printf("\bsi");
printf("\rha");
}

产生如下输出:

hai

\n是新线。