【问题标题】:utfcpp and Win32 wide APIutfcpp 和 Win32 宽 API
【发布时间】:2011-03-20 18:32:50
【问题描述】:

使用小型 utfcpp 库将我从广泛的 Windows API(FindFirstFileW 等)返回的所有内容转换为使用 utf16to8 的有效 UTF8 表示是否很好/安全/可行?

我想在内部使用 UTF8,但无法获得正确的输出(在另一次转换后通过 wcout 或普通 cout)。普通的 ASCII 字符当然可以,但 ñä 会搞砸。

或者有没有更简单的选择?

谢谢!

更新:感谢 Hans(下),我现在可以通过 Windows API 轻松实现 UTF8UTF16 转换。两种方式转换工作,但来自 UTF16 字符串的 UTF8 有一些额外的字符,可能会在以后给我带来一些麻烦......)。出于纯粹的友好,我会在这里分享它:)):

// UTF16 -> UTF8 conversion
std::string toUTF8( const std::wstring &input )
{
    // get length
    int length = WideCharToMultiByte( CP_UTF8, NULL,
                                      input.c_str(), input.size(),
                                      NULL, 0,
                                      NULL, NULL );
    if( !(length > 0) )
        return std::string();
    else
    {
        std::string result;
        result.resize( length );

        if( WideCharToMultiByte( CP_UTF8, NULL,
                                 input.c_str(), input.size(),
                                 &result[0], result.size(),
                                 NULL, NULL ) > 0 )
            return result;
        else
            throw std::runtime_error( "Failure to execute toUTF8: conversion failed." );
    }
}
// UTF8 -> UTF16 conversion
std::wstring toUTF16( const std::string &input )
{
    // get length
    int length = MultiByteToWideChar( CP_UTF8, NULL,
                                      input.c_str(), input.size(),
                                      NULL, 0 );
    if( !(length > 0) )
        return std::wstring();
    else
    {
        std::wstring result;
        result.resize( length );

        if( MultiByteToWideChar(CP_UTF8, NULL,
                                input.c_str(), input.size(),
                                &result[0], result.size()) > 0 )
            return result;
        else
            throw std::runtime_error( "Failure to execute toUTF16: conversion failed." );
    }
}

【问题讨论】:

    标签: c++ winapi utf-8 utf-16 wide-api


    【解决方案1】:

    Win32 API 已经具有执行此操作的函数 WideCharToMultiByte(),CodePage = CP_UTF8。使您不必依赖另一个库。

    您通常不能将结果与 wcout 一起使用。它的输出进入控制台,出于遗留原因,它使用 8 位 OEM 编码。您可以使用 SetConsoleCP() 更改代码页,65001 是 UTF-8 (CP_UTF8) 的代码页。

    您的下一个绊脚石将是用于控制台的字体。您必须对其进行更改,但要找到一种固定间距且具有涵盖 Unicode 的全套字形的字体将很困难。当您在输出中获得方形矩形时,您会看到字体问题。问号是编码问题。

    【讨论】:

    • 澄清一下:字体(至少是 TT 字体)允许您为字体不包含字形的代码点指定要显示的字形。这通常是一个空矩形,但基本上可以是字体设计师选择的任何东西。
    • 我认为这些是可用的,但我不知道它们是用于 UTF-8 -> UTF-16 转换的(我愚蠢地认为它们使用的是 UCS-2 编码)。控制台输出确实是一件乱七八糟的事情。也许我可以将 UTF-8 输出到一个文件并用 Notepad++ 打开它(它只是为了检查我的程序做了什么)?
    • 当然,应该可以。只要你能说服它这是一个 UTF-8 文件,它通常需要在文件开头有一个 BOM。先写0xef 0xbb 0xbf 确定。
    【解决方案2】:

    为什么要在内部使用 UTF8?您是否正在处理如此多的文本,以至于使用 UTF16 会产生不合理的内存需求?即使是这种情况,您还是最好还是使用宽字符,并以其他方式处理内存问题(使用磁盘缓存、更好的算法或数据结构)。

    在内部使用 Win32 API 原生的宽字符时,您的代码将更加简洁和容易处理,并且仅在读取或写入需要它的数据(例如 XML 文件或 REST API)时进行 UTF8 转换。

    您的问题也可能出现在您将输出打印到控制台时,请参阅:Output unicode strings in Windows console app

    最后,我没有使用 utfcpp 库,但是使用 Win32 的 WideCharToMultiByteMultiByteToWideCharCP_UTF8 作为代码页执行 UTF8 转换相当简单。就我个人而言,我会进行一次性转换并使用 UTF16 格式的文本,直到需要时以 UTF8 格式输出或传输它。

    【讨论】:

    • 请注意,Windows 上的宽字符是 16 位的,因此必须编码为 UTF-16。这也是一种多字节编码。即使您可能不太可能遇到需要对两个 16 位字节进行编码的 Unicode 代码点,但它们确实存在,并且您不能假设每个 16 位值都是一个单独的字符。
    • 没错,主要的好处是 UTF16 是 Windows 的原生编码,使用它意味着在调用 API 时不必不断地与其他编码进行转换。
    • 我正在开发一个跨平台应用程序,在 linux 上 wchar_t 是 Windows 上的两倍。我只需要 win32 API 来处理文件名,其余的都很简单文本(仅限 ASCII 字符)。当一个简单的 std::string 就足够时,我认为没有理由处理双倍字节数。
    • 原因是 a) 在这种情况下,双倍的字节数是无关紧要的,除非它是一个巨大的数量或者你在一个非常有限的平台上,并且 b) 它是本机操作系统编码,因此更简单使用。基本上,我认为在没有外部要求的情况下使用 UTF8 并不值得付出额外的努力和复杂性。
    • 正如我所说,该应用程序是跨平台的,如果我想让它在任何非 Windows 系统上运行,我必须创建一个更大的抽象层。它是 UTF8 或 UTF16,但无论如何都必须转换一端。我没有深入研究 tchar 业务。
    猜你喜欢
    • 1970-01-01
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多