美文网首页
区分换行符

区分换行符

作者: BetterCV | 来源:发表于2020-04-27 10:28 被阅读0次
    crlf2.jpg

    区分换行符

    换行符的定义

    不考虑远古时代打印机,换行符在不同操作系统下定义不同:

    CR符号:16进制为0X0D,ASCII转义符号表示为\r,意为回车(Carriage Return)
    LF符号:16进制为0X0A,ASCII转义符号表示为\n,意为换行(Line Feed)

    Windows系统: 用CR LF两个符号,表示“行与行之间的间隔”。注意最后一行末尾没有换行符。
    Linux/MacOSX系统:用LF一个符号,表示“每行末尾符号”。注意最后一行末尾也有换行符。
    MacOS在OSX之前的版本:用CR符号。从OSX开始用LF。

    EditorConfig里应该配置换行符吗?

    .editorconfig文件中,设定end_of_linelfcrlf,分别表示Linux/MacOSX和Windows下的换行符。

    特定平台的文件,例如.sh.bat,个人觉得应该设定end_of_line

    但对于跨平台的文件,典型如C/C++的.h/.hpp/.c/.cpp/.cc文件,不应该设定end_of_line。例如Windows下仍然配置为lf,则一旦有中文注释,会编译报错,或编译通过但调试阶段显示异常,当前调试行和运行行不对应。

    P.S. 曾有讨论添加end_of_line=native的提议,但反对人数略多,官方否决了。

    应该在版本控制工具(svn, git等)的全局配置中,配置换行符设定。

    用cat命令显示换行符

    cat -A file
    (TODO)

    Vim状态栏显示的行尾换行符,解释

    [noeol]

    多行文本,相邻行之间用LF(16进制0x0A,转义符\n)分隔,最后一行末尾没有LF。

    通常产生原因:在Windows下创建文件,填写内容保存;同时,git的config中core.autocrlf没有设定,或设定为true;则执行git add和git commit后,存储该文件到index中是用LF替代CRLF的,并且最后一行末尾也不会自动追加LF。

    则在Linux下git clone后用Vim打开该文件,显示[noeol]。
    (但如果是在Windows下的Vim里查看,显示[noeol][dos])

    用Vim打开并保存后,会在最后一行后追加LF,使它变成unix格式。(Win和Linux下的Vim都会这么做)

    定义空行:除了
    Linux/MacOSX下:一个行,包括它的行尾换行符,则空行定义只有换行符的行。
    Windows下:一个行,不包括它的行尾换行符,则空行定义为不含任何字符的行。

    [noeol][dos]

    多行文本,行与行之间以CR LF分隔,最后一行末尾没有CR LF,也没有LF或CR。

    典型出现场景:
    Windows下的文件(换行符用CR LF),文件最后一行有内容而非空行;把这个文件拷贝到Linux/MacOSX下,用Vim打开,则显示[noeol][dos]。或者,这个文件在Windows下被Vim打开,也同样显示[noeol][dos]。

    用Vim打开后,最后一行新增一行然后保存,重新打开则显示[dos]。也就是Vim给新增的换行符,是根据已有的换行符(CR LF)来增加的。

    总结:dos的意思是“CR LF”作为换行符。

    [dos]状态

    多行文本,行与行之间用CR LF分隔,最后一行末尾有CR LF。或者说,在Windows上编辑该文件时,最后一行是空行。而按照Linux下换行符的定义,这个空行被“吃掉”,整个文本比Windows上少一行。

    Vim的set list命令

    这个命令估计主要是区分Tab和换行的,因此每行末尾(包括最后一行)后都显示$。并不能区分CR LF和LF,也不能区分最后一行末尾是否有换行符。

    vim中的^M符号

    在Vim中,^M是用来表示ASCII的13(\r,16进制为0x0D)的,而M是英文字母表中第13个字母。

    因此原因也不难猜到:产生文本文件时用\r\n作为换行符了(通常是在Windows下产生),并且原封不动拷贝到Linux下(或是在Windows下用vim/gvim查看),Vim把\n当做换行符处理,而把\r当做普通字符予以显示,显示的效果就是^M

    git中的换行符配置

    需要明确,一个git repo它的工作区和索引区使用相互独立的换行符规则。
    也即:git add & git commit,提交代码,根据autocrlf做转换;git clone/git pull,根据autocrlf

    1. AutoCRLF
    #提交时转换为LF,检出时转换为CRLF
    git config --global core.autocrlf true
    
    #提交时转换为LF,检出时不转换
    git config --global core.autocrlf input   
    
    #提交检出均不转换
    git config --global core.autocrlf false
    

    (Windows下默认值为true)

    1. SafeCRLF
    #拒绝提交包含混合换行符的文件
    git config --global core.safecrlf true   
    
    #允许提交包含混合换行符的文件
    git config --global core.safecrlf false   
    
    #提交包含混合换行符的文件时给出警告
    git config --global core.safecrlf warn
    

    C/C++/Python中写入文件的语句

    常见的编程语言大都支持“把字符串写入文件”的功能。以C/C++为例,假设fout是输出文件指针,则:

    fprintf(fout, "hello\n"); //行尾写入\n单个符号。推荐
    fprintf(fout, "hello\r\n"); //行尾写入\r\n两个符号。不推荐。
    

    通常来说,编程语言中写入文件时,换行符用\n表示即可。有人可能担心说Windows下的换行符不是\r\n吗?以Windows10为例,用系统自带的Notepad软件打开以\r\n作为行尾的文本文件,状态栏显示的换行符并不是"CRLF",而是"Macintosh(CR)"。测试代码:

    #include <stdio.h>
    
    int main() {
        FILE* fp = fopen("out.txt", "w");
        fprintf(fp, "hello\r\n");
        fprintf(fp, "123 test\r\n");
        fprintf(fp, "oh yeah~~\r\n");
        fclose(fp);
    
        return 0;
    }
    

    编译运行后用Notepad自行打开"out.txt"查看即可发现,文本区域显示内容也和预期不太一样:

    hello
    
    123 test
    
    oh yeah~~
    
    
    

    用HxD64.exe查看"out.txt"的16进制表示:

    68 65 6C 6C 6F 0D 0D 0A 31 32 33 20 74 65 73 74 0D 0D 0A 6F 68 20 79 65 61 68 7E 7E 0D 0D 0A
    

    可以发现,行尾是"OD OD OA",也就是说:原本我们在C/C++代码中输出的\r\n,实际上写入到文件的字符是\r\r\n。什么意思呢?Visual Studio(这里我假定你用Windows时用的C/C++编译器为MSVC,用Cygwin的暂不考虑)的C/C++实现,把fprintf里的\n给强行换成\r\n了;而这也导致了“Notepad认为换行符是\r,也就是Macintosh的换行符,并且原本输出的两行之间多了一个空行”。

    相关文章

      网友评论

          本文标题:区分换行符

          本文链接:https://www.haomeiwen.com/subject/nvzewhtx.html