【问题标题】:ISO6937 to UTF8 give wrong results in C#ISO6937 到 UTF8 在 C# 中给出错误的结果
【发布时间】:2017-09-21 14:46:06
【问题描述】:

我正在从 C# 文件中读取一些二进制数据,还有需要正确解码的字符串。

例如 windows-1251 代码页我没有问题,但 ISO6937 的结果不正确 - 看起来 C# 忽略了 two byte chars (accent+char)。

我正在使用这种方式从字节中解码字符串:

Encoding.Convert(Encoding.GetEncoding("20269"), Encoding.UTF8, data)

例子:

克拉科夫

字节[] = 4B 72 61 6B C2 6F 77

结果 - Krak´ow

我做了一些研究,但我只找到了来自 MediaPortal at their GitHub 的一些代码,它们手动读取两个字节字符 - 这不是最好的方法。

是我做错了什么还是这是 Visual Studio 错误? (如果这不能正常工作,为什么他们赋予了 ISO6937 编码的能力?)

【问题讨论】:

  • 这不是“Visual Studio”错误,也不是 C# 错误; 可能 .NET 框架和/或 Windows 在该编码中存在故障。您是否 100% 确定这是该字符串的正确字节表示?我真的不熟悉 ISO6937。不过,老实说:如果您迁移到 UTF8,那对您来说会容易得多。至于“如果这不能正常工作,为什么他们赋予了 ISO6937 编码的能力?” - 如果它被窃听,可能是因为他们当时不知道它有故障。错误发生。
  • 感谢您的回答,不幸的是二进制数据不是我生成的,我别无选择,必须阅读它,因为它是由一些非常旧的应用程序保存的:(字符串也可以:4B 72 61 6B C2 6F 77 K rak [ ó ] w
  • 幸运的是,这个 实际上 看起来是一个很容易实现的编码 - 只有 13 个多字节标记,所以你可以只检查高位(或者见鬼,只是0xC1-0xCF 的特殊情况) - 替换图也很小 - en.wikipedia.org/wiki/ISO/IEC_6937 - 所以是的,我同意它通过 Encoding.GetEncoding 无法正常工作是非常令人烦恼和失望的,但是:它应该是一个小时的工作来解决它......
  • 使用ByteArrayToString 方法找到here,并运行它:Console.WriteLine(ByteArrayToString(Encoding.GetEncoding(20269).GetBytes("Kraków".ToCharArray())));,我得到的这些字节与你的不同:“4b72616b3f77”。也许我在转换 c# 字符时遗漏了一些东西?另请注意,我使用的是Encoding.GetEncoding(20269),因为Encoding.GetEncoding("20269") 为我抛出了异常。
  • @Quantic 我认为关键是:编码不起作用:) 检查维基百科,4B 72 61 6B C2 6F 77(来自 OP)确实是正确的字节

标签: c# string unicode encoding utf-8


【解决方案1】:

编码的Wikipedia page 确实暗示了潜在的问题。引用:“ISO/IEC 6937 不编码任何组合字符”。所以正式.NET 编码器按照标准所说的做,实际上它没有用。

这可以比链接的 GitHub 代码做得更好,更简洁的方法是制作自己的 Encoding 类。几乎所有的工作都可以委托给 .NET 编码,您只需要截取变音符号。这需要使用组合标记并将其与字母交换。像这样:

class ISO6937Encoding : Encoding {
    private Encoding enc = Encoding.GetEncoding(20269);

    public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) {
        int cnt = enc.GetChars(bytes, byteIndex, byteCount, chars, charIndex);
        for (int ix = 0; ix < byteCount; ix++, charIndex++) {
            int bx = byteIndex + ix;
            if (bytes[bx] >= 0xc1 && bytes[bx] <= 0xcf) {
                if (charIndex == chars.Length - 1) chars[charIndex] = '?';
                else {
                    const string subst = "\u0300\u0301\u0302\u0303\u0304\u0306\u0307\u0308?\u030a\u0337?\u030b\u0328\u030c";
                    chars[charIndex] = chars[charIndex + 1];
                    chars[charIndex + 1] = subst[bytes[bx] - 0xc1];
                    ++ix;
                    ++charIndex;
                }
            }
        }
        return cnt;
    }
    // Rest is boilerplate
    public override int GetByteCount(char[] chars, int index, int count) {
        return enc.GetByteCount(chars, index, count);
    }
    public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) {
        return enc.GetBytes(chars, charIndex, charCount, bytes, byteIndex);
    }
    public override int GetCharCount(byte[] bytes, int index, int count) {
        return enc.GetCharCount(bytes, index, count);
    }
    public override int GetMaxByteCount(int charCount) {
        return enc.GetMaxByteCount(charCount);
    }
    public override int GetMaxCharCount(int byteCount) {
        return enc.GetMaxCharCount(byteCount);
    }
}

未经过广泛测试。

【讨论】:

  • 感谢这段代码,我的测试后没有发现任何问题 - 比数百个案例/中断更漂亮和更清洁的解决方案 - 你是天才! :D
猜你喜欢
  • 2018-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 2020-04-01
  • 2011-11-15
相关资源
最近更新 更多