如何在 Visual C++ 中在 BSTR 和 32 位 Unicode 字符串之间进行转换?
How to convert between BSTR and 32-bit Unicode strings in Visual C++?
我有第 3 方代码,它对字符串进行 punycode(转义和非转义)。作为 Unicode input/output,它使用 32 位 Unicode 字符串 (uint32_t-based),而不是 16 位。我自己的 input/output 是 BSTR(UTF 16 位)。我应该如何在 32 位 Unicode 字符数组和 BSTR(双向)之间转换?
该代码应适用于 Visual C++ 6.0 及更高版本。
对于小于 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);
}
}
例如下面的代码应该在 Windows10 中显示一个笑脸:
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 个字节)。如果第一个字符在 0xD800
和 0xE000
之间,表示每个代码点 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);
我有第 3 方代码,它对字符串进行 punycode(转义和非转义)。作为 Unicode input/output,它使用 32 位 Unicode 字符串 (uint32_t-based),而不是 16 位。我自己的 input/output 是 BSTR(UTF 16 位)。我应该如何在 32 位 Unicode 字符数组和 BSTR(双向)之间转换?
该代码应适用于 Visual C++ 6.0 及更高版本。
对于小于 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);
}
}
例如下面的代码应该在 Windows10 中显示一个笑脸:
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 个字节)。如果第一个字符在 0xD800
和 0xE000
之间,表示每个代码点 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);