错误文件名的重新编码

Re-Encoding of wrong filenames

所以我也阅读了 Spolsky Article twice, this question 并尝试了很多。现在我来了。

我在具有 ISO-8859-1 区域设置的 Linux 机器上创建了一个目录结构的 tarball,并使用 7zip 在 Windows 上取消tarred .因此,当我在 Windows Explorer(以及我的 C# 程序中)中查看文件名时,文件名被打乱了:我希望看到德语变音符号 ü 的地方是 ³ - 难怪,因为文件名是使用 ISO-8859-1 代码页写入 tar 文件的,而 Windows 显然不知道这一点。

我想通过将文件重命名为正确的名称来解决此问题。所以我想我必须告诉程序 "read the filename, think of it as ISO-8859-1 and return every character as UTF-16 character."

我找到正确文件名的代码:

void Main()
{
    string[] files = Directory.GetFiles(@"C:\test", @"*", SearchOption.AllDirectories);
    var e1 = Encoding.GetEncoding("ISO-8859-1");
    var e2 = Encoding.GetEncoding("UTF-16");
    foreach (var f in files)
    {
        Console.WriteLine($"Source: {f}");
        var source = e1.GetBytes(f);
        var dest = Encoding.Convert(e1, e2, source);
        Console.WriteLine($"Result: {e2.GetString(dest)}");
    }
}

结果 - 什么都没发生:

Source: C:\test\Brief-mrl³.odt
Result: C:\test\Brief-mrl³.odt

预期结果:

Source: C:\test\Brief-mrl³.odt
Result: C:\test\Brief-mrlü.odt

当我交换 e1 和 e2 时,我得到了奇怪的结果。我的脑袋疼。我没有得到什么?

编辑:我知道之前犯了错误,但是现在我在Windows上的文件名有误我需要更正的机器。但是,它可能无法通过 Encoding-Class 求解。我找到了这个 blog post 并且作者说

It turns out, this isn't a problem with the encoding at all, but the same character address meaning different things to different character sets.

最后,他写了一个方法,用特定的不同字符替换130到173之间的字符。这对我来说看起来并不简单,但这可能是唯一的方法吗?有人可以对此发表评论吗?

经过更多阅读,我自己找到了解决方案。 This excellent article 有帮助。关键是:一旦使用了错误的编码,您只能猜测(或必须知道)究竟出了什么问题。如果你知道,你可以在代码中还原整个事情。

void Main()
{
    // We get the source string e.g. reading files from a directory. We see a "³" when 
    // we expect a German umlaut "ü". The reason can be a poorly configured smb share
    // on a Linux server or other problems.
    string source = "M³nch";

    // We are in a .NET program, so the source string (here in the 
    // program) is Unicode in UTF-16 encoding. I.e., the codepoints 
    // M, ³, n, c and h are encoded in UTF-16.

    byte[] bytesFromSource = Encoding.Unicode.GetBytes(source); // 
    // The source encoding is UTF-16, hence we get two bytes per character.

    // We accidently worked with the OEM850 Codepage, we now have look up the bytes of 
    // the codepoints on the OEM850 codepage: We convert our bytesFromSource to the wrong Codepage
    byte[] bytesInWrongCodepage = Encoding.Convert(Encoding.Unicode, Encoding.GetEncoding(850), bytesFromSource);

    // Here's the trick: Although converting to OEM850, we now assume that the bytes are Codepage ISO-8859-1.
    // We convert the bytes from ISO-8859-1 to Unicode.
    byte[] bytesFromCorrectCodepage = Encoding.Convert(Encoding.GetEncoding("ISO-8859-1"), Encoding.Unicode, bytesInWrongCodepage);

    // And finally we get the right character.
    string result = Encoding.Unicode.GetString(bytesFromCorrectCodepage);

    Console.WriteLine(result); // Münch
}

警告:不要运行此方法的结果。这可能会产生不可打印的字符或其他混乱。