代码之家  ›  专栏  ›  技术社区  ›  Brandon

UTF8ToUTF16故障

  •  0
  • Brandon  · 技术社区  · 10 年前

    我有下面的代码,它只是将UTF8转换为UTF16的三组函数,反之亦然。它使用3种不同的技术进行转换。。

    然而,所有这些都失败了:

    std::ostream& operator << (std::ostream& os, const std::string &data)
    {
        SetConsoleOutputCP(CP_UTF8);
        DWORD slen = data.size();
        WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), data.c_str(), data.size(), &slen, nullptr);
        return os;
    }
    
    std::wostream& operator <<(std::wostream& os, const std::wstring &data)
    {
        DWORD slen = data.size();
        WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), data.c_str(), slen, &slen, nullptr);
        return os;
    }
    
    std::wstring AUTF8ToUTF16(const std::string &data)
    {
        return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(data);
    }
    
    std::string AUTF16ToUTF8(const std::wstring &data)
    {
        return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(data);
    }
    
    std::wstring BUTF8ToUTF16(const std::string& utf8)
    {
        std::wstring utf16;
        int len = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);
        if (len > 1)
        {
            utf16.resize(len - 1);
            wchar_t* ptr = &utf16[0];
            MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, ptr, len);
        }
        return utf16;
    }
    
    std::string BUTF16ToUTF8(const std::wstring& utf16)
    {
        std::string utf8;
        int len = WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, 0, 0);
        if (len > 1)
        {
            utf8.resize(len - 1);
            char* ptr = &utf8[0];
            WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, ptr, len, 0, 0);
        }
        return utf8;
    }
    
    std::string CUTF16ToUTF8(const std::wstring &data)
    {
        std::string result;
        result.resize(std::wcstombs(nullptr, &data[0], data.size()));
        std::wcstombs(&result[0], &data[0], data.size());
        return result;
    }
    
    std::wstring CUTF8ToUTF16(const std::string &data)
    {
        std::wstring result;
        result.resize(std::mbstowcs(nullptr, &data[0], data.size()));
        std::mbstowcs(&result[0], &data[0], data.size());
        return result;
    }
    
    int main()
    {
        std::string str = "консоли";
    
        MessageBoxA(nullptr, str.c_str(), str.c_str(), 0); //Works Fine!
    
        std::wstring wstr = AUTF8ToUTF16(str);  //Crash!
        MessageBoxW(nullptr, wstr.c_str(), wstr.c_str(), 0); //Fail - Crash + Display nothing..
    
        wstr = BUTF8ToUTF16(str);
        MessageBoxW(nullptr, wstr.c_str(), wstr.c_str(), 0); //Fail - Random chars..
    
        wstr = CUTF8ToUTF16(str);
        MessageBoxW(nullptr, wstr.c_str(), wstr.c_str(), 0); //Fail - Question marks..
    
        std::cin.get();
    }
    

    上面唯一有效的是 MessageBoxA 。我不明白为什么,因为我被告知Windows会将所有内容都转换为UTF16,所以我为什么不能自己转换呢? 为什么我的转换都不起作用?

    我的代码不工作有什么原因吗?

    1 回复  |  直到 10 年前
        1
  •  2
  •   Remy Lebeau    10 年前

    所有方法失败的根本问题是它们需要 std::string 要进行UTF-8编码,但 std::string str = "консоли" 不是UTF-8编码的,除非将.cpp文件保存为UTF-8并将编译器的默认代码页配置为UTF-8。 在大多数C++11编译器中,可以使用 u8 强制字符串使用UTF-8的前缀:

    std::string str = u8"консоли";
    

    然而,VS 2013尚不支持该功能:

    Support For C++11 Features

    Unicode字符串文字 2010年编号 2012年无 2013年编号

    Windows本身在大多数API函数中不支持UTF-8 char* 作为输入(异常为 MultiByteToWideChar() 使用时 CP_UTF8 ). 当您拨打 A 函数,它调用相应的 W 函数内部,转换任何 字符* 使用Windows的默认代码页将数据发送到UTF-16( CP_ACP ). 所以当你使用非 CP_ACP 具有期望的函数的数据。因此, MessageBoxA() 仅当.cpp文件和编译器使用的代码页与 CP_ACP 所以没有固定的 字符* 数据匹配什么 消息框A() 正在等待。

    我不知道为什么 AUTF8ToUTF16() 正在崩溃,这可能是在处理坏数据时编译器STL实现中的错误。

    BUTF8ToUTF16() 不是在处理这个案子 the documentation :“如果输入的字节/字符序列无效,则返回UTF编码的U+FFFD。”此外,您的实现不是最佳的。使用 length() 而不是 -1 以避免处理空终止符问题。

    CUTF8ToUTF16() 没有进行任何错误处理或验证。然而,在大多数库中,将无效输入转换为问号或U+FFFD是非常常见的。