【问题标题】:How to make sure all my source files stay UTF-8 with Unix line endings?如何确保我的所有源文件都保持 UTF-8 和 Unix 行结尾?
【发布时间】:2012-01-22 13:02:34
【问题描述】:

我正在寻找一些适用于 Linux 的命令行工具,它们可以帮助我检测和转换来自 iso-8859-1windows-1252 等字符集的文件到 utf-8 以及从 Windows 行尾到 Unix 行尾。

我需要这个的原因是我正在通过 SFTP 在 Linux 服务器上使用 Windows 上的编辑器(如 Sublime Text)处理项目,这些编辑器不断地搞砸这些事情。现在我猜我的文件大约有一半是 utf-8,其余的是 iso-8859-1windows-1252似乎 Sublime Text 只是在我保存文件时根据文件包含的符号选择字符集。即使我在选项中指定默认行尾为 LF,行尾始终是 Windows 行尾,所以我的文件中大约有一半有 LF,一半是 CRLF.

所以我至少需要一个工具,它可以递归扫描我的项目文件夹,并提醒我有 utf-8LF 行结尾的文件,这样我就可以在我将更改提交到 GIT 之前手动修复它。

也欢迎任何有关该主题的 cmets 和个人经验。

谢谢


编辑:我有一个临时解决方案,我使用treefile 输出有关我项目中每个文件的信息,但这有点不靠谱.如果我不包括 file-i 选项,那么我的很多文件都会得到不同的输出,例如 ASCII C++ 程序文本HTML 文档文本英文文本等:

$ tree -f -i -a -I node_modules --noreport -n | xargs 文件 | grep -v 目录 ./config.json:ASCII C++ 程序文本 ./debugserver.sh:ASCII 文本 ./.gitignore:ASCII 文本,没有行终止符 ./lib/config.js:ASCII 文本 ./lib/database.js:ASCII 文本 ./lib/get_input.js:ASCII 文本 ./lib/models/stream.js:ASCII 英文文本 ./lib/serverconfig.js:ASCII 文本 ./lib/server.js:ASCII 文本 ./package.json:ASCII 文本 ./public/index.html:HTML 文档文本 ./src/config.coffee:ASCII 英文文本 ./src/database.coffee:ASCII 英文文本 ./src/get_input.coffee:ASCII 英文文本,带有 CRLF 行终止符 ./src/jtv.coffee:ASCII 英文文本 ./src/models/stream.coffee:ASCII 英文文本 ./src/server.coffee:ASCII 文本 ./src/serverconfig.coffee:ASCII 文本 ./testserver.sh:ASCII 文本 ./vendor/minify.json.js:ASCII C++ 程序文本,带有 CRLF 行终止符

但如果我确实包含 -i 它不会显示行终止符:

$ tree -f -i -a -I node_modules --noreport -n | xargs 文件 -i | grep -v 目录 ./config.json: 文本/x-c++; charset=us-ascii ./debugserver.sh:文本/纯文本; charset=us-ascii ./.gitignore:文本/纯文本; charset=us-ascii ./lib/config.js:文本/纯文本; charset=us-ascii ./lib/database.js:文本/纯文本; charset=us-ascii ./lib/get_input.js:文本/纯文本; charset=us-ascii ./lib/models/stream.js:文本/纯文本; charset=us-ascii ./lib/serverconfig.js:文本/纯文本; charset=us-ascii ./lib/server.js:文本/纯文本; charset=us-ascii ./package.json:文本/纯文本; charset=us-ascii ./public/index.html:文本/html; charset=us-ascii ./src/config.coffee:文本/纯文本; charset=us-ascii ./src/database.coffee:文本/纯文本; charset=us-ascii ./src/get_input.coffee:文本/纯文本; charset=us-ascii ./src/jtv.coffee:文本/纯文本; charset=us-ascii ./src/models/stream.coffee:文本/纯文本; charset=us-ascii ./src/server.coffee:文本/纯文本; charset=us-ascii ./src/serverconfig.coffee:文本/纯文本; charset=us-ascii ./testserver.sh:文本/纯文本; charset=us-ascii ./vendor/minify.json.js: text/x-c++; charset=us-ascii

还有为什么它显示 charset=us-ascii 而不是 utf-8text/x-c++ 是什么?有没有办法只为每个文件输出charset=utf-8line-terminators=LF

【问题讨论】:

  • 作为一种解决方法,也许您可​​以包含一个带有明显非 ASCII 字符代码的注释(想到版权符号)并保存为 UTF-8 - 也许这对于 Sublime Text 来说已经足够了不要再猜测了。
  • 为了上帝的爱,我也无法让 Sublime Text 仅仅使用该死的 Unix 换行符!! "default_line_ending": "unix" 应该可以工作!

标签: unix command-line character-encoding sublimetext line-endings


【解决方案1】:

我最终得到的解决方案是两个 Sublime Text 2 插件 "EncodingHelper""LineEndings"。我现在在状态栏中同时获得文件编码和行尾:

如果编码错误,我可以File->Save with Encoding。如果行尾错误,后一个插件会附带更改行尾的命令:

【讨论】:

    【解决方案2】:

    如果文件没有 BOM,并且在 file 查看的文本量中没有“有趣的字符”,file 会得出结论,它是 ASCII ISO-646 -- 严格的UTF-8 的子集。您可能会发现将 BOM 放在所有文件上会鼓励所有这些 Windows 工具正常运行; UTF-8 文件上的 BOM 约定起源于 Windows。或者它可能会使事情变得更糟。至于 x/c++,好吧,那只是 file 试图提供帮助,但失败了。你的 javascript 中有一些看起来像 C++ 的东西。

    Apache Tika 有一个编码检测器;您甚至可以使用它附带的命令行驱动程序作为file 的替代品。它将坚持 MIME 类型,而不是转向 C++。

    【讨论】:

    • 感谢您的解释。至于使用 Apache Tika 的编码检测器……感觉就像买了一艘游轮穿越水坑。我显然正在寻找的是一个用于分析文件的命令行工具,它将为我提供我正在寻找的输出,即字符编码和行终止符
    • 只要确保水坑没有礁石。真的,使用他们的 CLI 只是“使用命令”。我不记得 icu4c 是否包含一个具有竞争力的命令,或者使用带有正确选项的 iconv 是否会给非 UTF-8 带来明显错误。
    • 请注意file 有时会使用相当粗略的启发式方法——您的x-c++ 示例表明它做出了错误的猜测。如果您确切知道要查找的内容,一些简单的grep 命令可以帮助您对文件进行分类。
    【解决方案3】:

    不要使用file,而是尝试使用自定义程序来检查您想要的内容。这里有一个快速hack,主要基于someGooglehits,是@ikegami顺便写的。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Encode qw( decode );
    
    use vars (qw(@ARGV));
    
    @ARGV > 0 or die "Usage: $0 files ...\n";
    
    for my $filename (@ARGV)
    {
        my $terminator = 'CRLF';
        my $charset = 'UTF-8';
        local $/;
        undef $/;
        my $file;
        if (open (F, "<", $filename))
        {
            $file = <F>;
            close F;    
            # Don't print bogus data e.g. for directories
            unless (defined $file)
            {
                warn "$0: Skipping $filename: $!\n;
                next;
            }
        }
        else
        {
            warn "$0: Could not open $filename: $!\n";
            next;
        }
    
        my $have_crlf = ($file =~ /\r\n/);
        my $have_cr = ($file =~ /\r(?!\n)/);
        my $have_lf = ($file =~ /(?!\r\n).\n/);
        my $sum = $have_crlf + $have_cr + $have_lf;
        if ($sum == 0)
        {
            $terminator = "no";
        }
        elsif ($sum > 2)
        {
            $terminator = "mixed";
        }
        elsif ($have_cr)    
        {
            $terminator = "CR";
        }
        elsif ($have_lf)
        {
            $terminator = "LF";
        }
    
        $charset = 'ASCII' unless ($file =~ /[^\000-\177]/);
    
        $charset = 'unknown'
            unless eval { decode('UTF-8', $file, Encode::FB_CROAK); 1 };
    
        print "$filename: charset $charset, $terminator line endings\n";
    }
    

    请注意,这没有传统 8 位编码的概念 - 如果它既不是纯 7 位 ASCII 也不是正确的 UTF-8,它将简单地抛出 unknown

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2015-07-31
      • 1970-01-01
      • 2020-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多