如何在Visual C ++中转换BSTR和32位Unicode字符串?

时间:2017-08-31 13:48:36

标签: c++ unicode bstr

我有第三方代码,用于限制字符串(escapes和unescapes)。作为Unicode输入/输出,它使用32位Unicode字符串(基于uint32_t),而不是16位。我自己的输入/输出是BSTR(UTF 16位)。我应该如何在32位Unicode字符数组和BSTR(两个方向)之间进行转换?

代码应该在Visual C ++ 6.0及更高版本中运行。

1 个答案:

答案 0 :(得分:1)

对于小于0xFFFF的字符,UTF16与UTF32相同。您可以使用以下转换在Windows中显示UTF-32代码。

请注意,这是基于维基百科UTF16的文章。我没有添加任何错误检查,它需要有效的代码。

void get_utf16(std::wstring &str, int ch32)
{
    const int mask = (1 << 10) - 1;
    if(ch32 < 0xFFFF)
    {
        str.push_back((wchar_t)ch32);
    }
    else
    {
        ch32 -= 0x10000;
        int hi = (ch32 >> 10) & mask;
        int lo = ch32 & mask;

        hi += 0xD800;
        lo += 0xDC00;

        str.push_back((wchar_t)hi);
        str.push_back((wchar_t)lo);
    }
}

例如,以下代码应在Windows 10中显示笑脸:

std::wstring str;
get_utf16(str, 0x1f600);
::MessageBoxW(0, str.c_str(), 0, 0);

<小时/> 编辑:

从UTF-32代码点数组中获取UTF-16,反向操作:

UTF-16字符串可以是一个wchar_t个字符长(每个代码点2个字节),或者连接在一起的2个wchar_t个字符(每个代码点4个字节)。如果第一个字符在0xD8000xE000之间,则表示每个代码点有4个字节。

bool get_str_utf16(std::wstring &dst, const std::vector<unsigned int> &src)
{
    const int mask = (1 << 10) - 1;
    for(size_t i = 0; i < src.size(); i++)
    {
        unsigned int ch32 = src[i];
        ////check for invalid range
        //if(ch32 > 0x10FFFF || (ch32 >= 0xD800 && ch32 < 0xE000))
        //{
        //  cout << "invalid code point\n";
        //  return false;
        //}

        if(ch32 > 0x10000)
        {
            ch32 -= 0x10000;
            int hi = (ch32 >> 10) & mask;
            int lo = ch32 & mask;
            hi += 0xD800;
            lo += 0xDC00;
            dst.push_back((wchar_t)hi);
            dst.push_back((wchar_t)lo);
        }
        else
        {
            dst.push_back((wchar_t)ch32);
        }
    }
    return true;
}

void get_str_utf32(std::vector<unsigned int> &dst, const std::wstring &src)
{
    for(unsigned i = 0; i < src.size(); i++)
    {
        const wchar_t ch = src[i];
        if(ch >= 0xD800 && ch < 0xE000)
        {
            //this character is joined with the next character
            if(i < src.size() - 1)
            {
                unsigned int hi = src[i]; i++;
                unsigned int lo = src[i];
                hi -= 0xD800;
                lo -= 0xDC00;
                unsigned int u32 = 0x10000 + (hi << 10) + lo;
                dst.push_back(u32);
            }
        }
        else
        {
            dst.push_back(ch);
        }
    }
}

示例:

std::wstring u16 = L"123456";

std::vector<unsigned int> u32;
get_str_utf32(u32, u16);
cout << "\n";

cout << "UTF-32 result: ";
for(auto e : u32)
    printf("0x%X ", e);
cout << "\n";

std::wstring test;
get_str_utf16(test, u32);
MessageBox(0, test.c_str(), (u16 == test) ? L"OK" : L"ERROR", 0);