【发布时间】:2010-11-19 18:28:01
【问题描述】:
\r 和 \n 有何不同?我认为这与 Unix、Windows 和 Mac 有关,但我不确定它们到底有什么不同,以及在正则表达式中搜索/匹配哪个。
【问题讨论】:
-
这需要一个语言标签。不同的语言对
'\n'有不同的解释。
标签: special-characters line-endings
\r 和 \n 有何不同?我认为这与 Unix、Windows 和 Mac 有关,但我不确定它们到底有什么不同,以及在正则表达式中搜索/匹配哪个。
【问题讨论】:
'\n'有不同的解释。
标签: special-characters line-endings
\r 是回车; \n 是换行(换行)...取决于操作系统的每个含义。阅读此article,了解更多关于 C 中 '\n' 和 '\r\n' ... 之间的区别。
【讨论】:
在 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 是控制光标位置以更新屏幕上已有文本的方法之一。
但大多数时候,您实际上只是想转到下一行。一些系统不需要一对控制字符,而是只允许一个或另一个。例如:
U+0085 NEXT LINE,但实际的 EBCDIC 值是 0x15。为什么不同的系统选择不同的方法?仅仅是因为没有通用的标准。你的键盘可能会说“Enter”,旧键盘曾经说“Return”,这是回车的缩写。事实上,在串行终端上,按 Return 实际上会发送 CR 字符。如果您正在编写文本编辑器,则很容易使用从终端输入的字符。也许这就是为什么较旧的 Mac 只使用 CR。
现在我们有了standards,还有更多种方式来表示换行符。虽然在野外极为罕见,但 Unicode 有一些新字符,例如:
U+2028 LINE SEPARATORU+2029 PARAGRAPH SEPARATOR甚至在 Unicode 出现之前,程序员就想要用简单的方法来表示一些最有用的控制代码,而不必担心底层字符集。 C 有几个转义序列来表示控制代码:
\a(用于提醒)敲响电传打字机铃声或使终端发出哔哔声\f(换页)移动到下一页的开头\t(用于制表符)将打印头移动到下一个水平制表符位置(此列表故意不完整。)
这种映射发生在编译时——编译器看到\a 并放置用于响铃的任何魔法值。
请注意,这些助记符中的大多数都与 ASCII 控制代码直接相关。例如,\a 将映射到 0x07 BEL。可以为主机字符集(例如 EBCDIC)使用非 ASCII 字符的系统编写编译器。大多数具有特定助记符的控制码都可以映射到其他字符集中的控制码。
嘘!便携性!
嗯,差不多。在 C 语言中,我可以编写printf("\aHello, World!");,它会响铃(或哔哔声)并输出一条消息。但是如果我想在下一行打印一些东西,我仍然需要知道主机平台需要什么才能移动到下一行输出。 CR LF?铬?如果?荷兰?还有什么?便携性就这么多。
C 有两种 I/O 模式:二进制和文本。在二进制模式下,发送的任何数据都会按原样传输。但在文本模式下,有一个 run-time 翻译将特殊字符转换为主机平台需要的任何新行(反之亦然)。
太好了,那么特殊字符是什么?
嗯,这也是依赖于实现的,但是有一种独立于实现的方式来指定它:\n。它通常被称为“换行符”。
这是一个微妙但重要的点: \n 在编译时 映射到一个实现定义 字符值(在文本模式)然后在运行时再次映射到底层平台移动到下一行所需的实际字符(或字符序列)。
\n 与所有其他反斜杠文字不同,因为涉及两个映射。这种两步映射使\n 与\r 明显不同,\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。【讨论】:
'\n' 的警告是针对C 和C++ 的。如果 Python 保证 '\n' 实际上是换行符,我不会感到惊讶。许多网络协议使用 CR+LF 作为行分隔符。所以每个 HTTP 标头都应该以 CR+LF 结尾,但我不知道规范对“有效负载”中的文本行有何规定。
\r 用于回车。 (ASCII 值为 13) \n 用于换行。 (ASCII值为10)
【讨论】:
在 C# 中,我发现他们在字符串中使用 \r\n。
【讨论】:
\r 用于指向一行的开头,可以从那里替换文本,例如
main()
{
printf("\nab");
printf("\bsi");
printf("\rha");
}
产生这个输出:
hai
\n 用于换行。
【讨论】:
他们是不同的角色。 \r 是回车,\n 是换行。
在“旧”打印机上,\r 将打印头送回行首,\n 将纸张推进一行。因此,两者都是在下一行开始打印所必需的。
现在显然这有点无关紧要了,尽管取决于控制台,您仍然可以使用 \r 移动到行首并覆盖现有文本。
更重要的是,Unix 倾向于使用\n 作为行分隔符; Windows 倾向于使用 \r\n 作为行分隔符,而 Mac(直到 OS 9)使用 使用 \r 作为行分隔符。 (Mac OS X 是 Unix-y,所以使用 \n 代替;在某些兼容性情况下,可能会使用 \r 代替。)
有关详细信息,请参阅Wikipedia newline article。
编辑:这是语言敏感的。例如,在 C# 和 Java 中,\nalways 表示 Unicode U+000A,它被定义为换行符。在 C 和 C++ 中,水有点混浊,因为含义是特定于平台的。详情见 cmets。
【讨论】:
\n 不一定是 ASCII 换行符。这是一个 C 和 C++ 约定,用于在文本模式下执行 I/O 时引用主机平台的行分隔符。大多数实现碰巧使用\n 的ASCII 换行符,但我认为C 或C++ 标准实际上并不要求这样做。如果要换行,请使用\n。如果你想要换行,你使用\x0A。相比之下\r 是应该是ASCII回车,不管实现。
\n is 保证为换行符(第 2.4.4.4 节)。当然,如果 OP 指定了平台,那就太好了……此外,我认为这种详细程度对于仅仅询问差异的人来说会更令人困惑而不是有用。
"\n" => 换行或换行 (语义)
基于 Unix 的系统仅使用“\n”来结束一行文本。
【讨论】:
除了@Jon Skeet 的回答:
传统上 Windows 使用 \r\n、Unix \n 和 Mac \r,但较新的 Mac 使用 \n,因为它们是基于 unix 的。
【讨论】:
简而言之,\r 的 ASCII 值为 13 (CR),\n 的 ASCII 值为 10 (LF)。 Mac 使用 CR 作为行分隔符(至少以前是这样,我不确定现代 Mac 是否如此),*nix 使用 LF,而 Windows 两者都使用 (CRLF)。
【讨论】: