换行符知多少

Forums: 

img: 

在遇到困难之前, us 总会认为自己已经懂得了“宇宙的真理”。me 相信很多人分不清回车和换行,或是说对很多人来说它们都是一样的。键盘的回车键上有个 return ↵ 或是 enter ↵ 标志,在编辑器中敲击回车键显示一个换行的效果。尼玛,O__O"…

c 语言中,或是 ascii 码中,回车符 carriage return (CR) 和换行 line feed (LF, 因为 c 的缘故有时候又写作 newline NL) 是两个不同的字符。 在 unix 系统中 LF 就是换行, 然而在 windows 系统下 CR LF 两个字符才显示一个换行, mac 下貌似是 CR 表示换行。 这没有所谓的对错一说, 不同的系统就是有这样不同的实现, 有时候这会成为一个问题。这里也简单描述一下 c 对回车符 CR 和换行符 LF 的记法:\r 和 \n ,这种转义的记法几乎为后来的所有编程语言所采纳。

不同的换行实现

下面是一个简单的 c 程序:

  1. #include <stdio.h>
  2.  
  3. int main(int argc, char *argv[])
  4. {
  5.     printf("abc\n123");
  6.     return 0;
  7. }

程序的思路太简单了,就是输出 abc\n123 到终端。这里是几个字符来着?毫无疑问是 7 个, 6 个可见字符 + 1 个换行符!在 unix 或是 linux 下,编译 $ gcc hello.c ,然后将结果重定向到 out.txt 文件中 $ ./a.exe > out.txt ,最后统计一下字符数 $ wc out.txt 会发现这里有 7 个字节(一个字节一个字符)! 然而,如果在 windows 下编译和运行以及重定向后,文件中有 8 个字符,原来的 \n 前面多了一个 \r 。

也就是 linux 下的 c 和 windows 下的 c 对于换行 \n 有自己不同的实现, 不管如何, 当 us 看 out.txt 总是会发现在该换行的地方换行了。

可能存在的问题

在 windows 下除了运行原生的 exe 之外, me 们还可能使用 mingw 或是 cygwin 运行 linux(不再重提 unix) 下的程序。在对换行的解释上, mingw 会按照 windows 的传统, 而 cygwin 则还是遵循 linux 的传统,所以, 当 me 们使用 cygwin 环境运行 linux 程序的时候,生成的 exe 中的换行只是一个 \n 字符。 其实这不算神马大问题,当 me 们将结果写到文件中,一般的稍微算得上编辑器的编辑器都会自动识别 \n 为换行(显示换行效果), 然而就是 windows 自带的记事本 notepad 不能识别 \n 为换行,然后 u 就发现一个文件是长长的一行。

其实 windows 的 cmd 是识别 \n 为换行的, 所以如果运行 cygwin 的 exe 发现是有换行效果的; 但是重定向到一个文件中,使用记事本 notepad 打开的时候却没有,O__O"… 这种差异让人很不爽。当然如果 u 不适用 notepad 的话,其实就么有太大的问题,然而很多小白对于 txt 文件默认都是用的 notepad 打开。

解决方案

解决方案其实应该很多, 实际上就是将一个 \n 换行的文件转换为 \r\n 的文件。 可以自己写个 c 的小程序去解决,或是使用 linux 或是 cygwin 下就有的 unix2dos 命令来解决。不过这两种方法的缺点是, me 在 windows 下写 bat 的时候,必须附带了这个转换程序,未免有点麻烦。

windows 下有自己的解决思路:

> type unix_file | find "" /V > dos_file

上面这个命令就可以将 unix_file 中的 \n 替换成 \r\n 然后输出至 dos_file 中。

假设有一个 cygwin 程序 hello.exe ,本程序默认输出至控制台, 但是 me 们想将内容输出到 out.txt 中,而且换行符是 \r\n 。可以这样做:

$ ./hello.exe | find "" /V > out.txt

为嘛可以像上面的两种方法实现? 因为 cmd 和 type 命令本身是识别 \n 为换行符的!O__O"…

怎么看“不可见字符”

尼玛,\r \n \t 这些不可见字符,当 me 们在一个文件中“看”它们的时候,能感觉到有空白效果,或是换行的效果,但是看到空白, me 应该猜是空格呢还是 \t 呢?看到换行,是猜 \n 呢?还是 \r 呢?还是 \r\n 呢?眼看不出来 , me 们得借助工具看。 od 就是一个很好的工具。

$ od -c out.txt

将文件 out.txt 逐个字节滴以字符滴形式显示出来,比如上面的 abc\n123 的显示效果是:

0000000   a   b   c  \n   1   2   3
0000007

或是:

0000000   a   b   c  \r  \n   1   2   3
0000010

精诚所至,金石为开

windows下写个 unix2dos 程序

前面说了 unix2dos 是将文件中的 \n 换成 \r\n ,现在在 windows 下实现一个这样的程序:

  1. #include <stdio.h>
  2.  
  3. int main(int argc, char *argv[])
  4. {
  5.     int ch;
  6.     while((ch = getchar()) != EOF){
  7.         putchar(ch);
  8.     }
  9.     return 0;
  10. }

上面的程序在 windows 下使用 vc 或是 mingw 编译,而不要使用 cygwin 环境, 这个程序就可以将 \n 换成 \r\n 。也许 u 会奇怪 : 这个程序不是原模原样复制吗? 怎么会将 \n 替换成 \r\n 呢? 最初 me 也纳闷, 不过细细想来, 这岂不就是 windows 下对换行的解释? 也就是说, 当 windows 遇到 \n 或是 \r\n 都会理解成换行,当它输出换行的时候就是输出两个字符 \r\n 。 就是这么奇葩!O__O"…

精诚所至,金石为开