摘要
windows换行符:\r\n
unix:\n
仅仅因为这个小小的不同,文件在多个系统环境下编辑过后,可能会发现文件的显示除了问题。最糟糕的是同一份文件里面既有windows的\r\rn风格的换行,又有unix的\n风格的换行。用vim打开这样一份混合换行风格的文件,会现多余的^M符号(不影响编译,但是很难看)。
问题
在不同系统下使用不同的文本编辑器边界源代码的时候,各编辑器可能会使用一些不同的标准,导致的结果是A编辑器编辑过的文件,在B编辑器里面显示异常。如下图所示,
这份源文件最初版本是使用vim创建的,中途使用了Notepad++编辑过后,再拿到vim下发现文件各行行尾出现了异常字符^M。
分析
将问题源文件test.c拷贝一份,生成一个正常显示的test-copy.c文件。
使用hexdump命令查看两份文件,逐字节的比较异同
#hexdump -c -n 100 test.c
#hexdump -c -n 100 test-copy.c
上图蓝色线表示了问题的所在。
文件中的换行应该由连续的两个字符’\r’,’\n’表示,而不是一个’\n’。
修复
修复思路:以二进制形式打开文件,逐字节读取,如果读到’\n’,那么检查前一个字符,如果前一个字符不是’\r’,那么插入一个’\r’。
/* Usage: command filename */
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *fin, *fout;
char fn[256];
unsigned char c;
int r;
int lastChar = 0;
if (argc <= 1) {
printf("Usage: command filename.\n");
return 0;
}
fin = fopen(argv[1], "rb");
strcpy(fn, argv[1]);
strcat(fn, ".tmp");
fout = fopen(fn, "wb");
while (!feof(fin)) {
if (fread(&c, sizeof(char), 1, fin) != 1)
break;
if (c == '\n') {
if (lastChar != '\r') {
char p = '\r';
fwrite(&p, sizeof(char), 1, fout);
}
}
fwrite(&c, sizeof(char), 1, fout);
lastChar = c;
}
fclose(fin);
fclose(fout);
{
char cmd[256] = "";
strcpy(cmd, "mv ");
strcat(cmd, fn);
strcat(cmd, " ");
strcat(cmd, argv[1]);
system(cmd);
}
return 0;
}
结果
以之前遇到的几个显示异常的源文件为用例,利用上面给出的程序,可以修复编辑器换行不一致,导致产生额外的'^M'字符的问题。
补记:
2013/03/19
其实,随linux系统发布的程序库里面有命令unix2dos/dos2unix专门处理此类问题,且实现的功能更完善。unix2dos代码是开源的,有兴趣可以下载来看看。