是否可以以独立于平台的方式将std::string中的UTF8字符串转换为std::wstring,反之亦然?在Windows应用程序中,我会使用MultiByteToWideChar和WideCharToMultiByte。但是,代码是为多个OSes编译的,我只能使用标准的C++库。
发布于 2008-09-29 14:00:12
问题定义明确指出8位字符编码是UTF-8。这使得这是一个微不足道的问题;它所需要的就是从一种UTF规范转换到另一种UTF规范。
只要看看这些维基百科页面上针对UTF-8、UTF-16和UTF-32的编码就可以了。
原理很简单-根据一个UTF规范遍历输入并组装一个32位Unicode代码点,然后根据另一个规范发出代码点。各个代码点不需要转换,这是任何其他字符编码都需要的;这就是为什么这是一个简单的问题。
下面是wchar_t
到UTF8转换的快速实现,反之亦然。它假设输入已经被正确编码--“垃圾输入,垃圾输出”这句老话适用于这里。我认为验证编码最好作为一个单独的步骤来完成。
std::string wchar_to_UTF8(const wchar_t * in)
{
std::string out;
unsigned int codepoint = 0;
for (in; *in != 0; ++in)
{
if (*in >= 0xd800 && *in <= 0xdbff)
codepoint = ((*in - 0xd800) << 10) + 0x10000;
else
{
if (*in >= 0xdc00 && *in <= 0xdfff)
codepoint |= *in - 0xdc00;
else
codepoint = *in;
if (codepoint <= 0x7f)
out.append(1, static_cast<char>(codepoint));
else if (codepoint <= 0x7ff)
{
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else if (codepoint <= 0xffff)
{
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else
{
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
codepoint = 0;
}
}
return out;
}
上面的代码同时适用于UTF-16和UTF-32输入,原因很简单,因为从d800
到dfff
的范围都是无效的代码点;它们表明您正在对UTF-16进行解码。如果你知道wchar_t
是32位的,那么你可以删除一些代码来优化函数。
std::wstring UTF8_to_wchar(const char * in)
{
std::wstring out;
unsigned int codepoint;
while (*in != 0)
{
unsigned char ch = static_cast<unsigned char>(*in);
if (ch <= 0x7f)
codepoint = ch;
else if (ch <= 0xbf)
codepoint = (codepoint << 6) | (ch & 0x3f);
else if (ch <= 0xdf)
codepoint = ch & 0x1f;
else if (ch <= 0xef)
codepoint = ch & 0x0f;
else
codepoint = ch & 0x07;
++in;
if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
{
if (sizeof(wchar_t) > 2)
out.append(1, static_cast<wchar_t>(codepoint));
else if (codepoint > 0xffff)
{
out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
}
else if (codepoint < 0xd800 || codepoint >= 0xe000)
out.append(1, static_cast<wchar_t>(codepoint));
}
}
return out;
}
同样,如果你知道wchar_t
是32位的,你可以从这个函数中删除一些代码,但在这种情况下,它应该没有任何区别。表达式sizeof(wchar_t) > 2
在编译时是已知的,因此任何像样的编译器都会识别死代码并将其删除。
发布于 2008-09-29 14:42:31
发布于 2008-09-29 13:36:26
您可以从Boost serialization library中提取utf8_codecvt_facet
。
他们的用法示例:
typedef wchar_t ucs4_t;
std::locale old_locale;
std::locale utf8_locale(old_locale,new utf8_codecvt_facet<ucs4_t>);
// Set a New global locale
std::locale::global(utf8_locale);
// Send the UCS-4 data out, converting to UTF-8
{
std::wofstream ofs("data.ucd");
ofs.imbue(utf8_locale);
std::copy(ucs4_data.begin(),ucs4_data.end(),
std::ostream_iterator<ucs4_t,ucs4_t>(ofs));
}
// Read the UTF-8 data back in, converting to UCS-4 on the way in
std::vector<ucs4_t> from_file;
{
std::wifstream ifs("data.ucd");
ifs.imbue(utf8_locale);
ucs4_t item = 0;
while (ifs >> item) from_file.push_back(item);
}
在boost源中查找utf8_codecvt_facet.hpp
和utf8_codecvt_facet.cpp
文件。
https://stackoverflow.com/questions/148403
复制相似问题