首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >UTF8与STL中的宽字符之间的转换

UTF8与STL中的宽字符之间的转换
EN

Stack Overflow用户
提问于 2008-09-29 12:03:23
回答 7查看 86.5K关注 0票数 79

是否可以以独立于平台的方式将std::string中的UTF8字符串转换为std::wstring,反之亦然?在Windows应用程序中,我会使用MultiByteToWideChar和WideCharToMultiByte。但是,代码是为多个OSes编译的,我只能使用标准的C++库。

EN

回答 7

Stack Overflow用户

发布于 2008-09-29 14:00:12

问题定义明确指出8位字符编码是UTF-8。这使得这是一个微不足道的问题;它所需要的就是从一种UTF规范转换到另一种UTF规范。

只要看看这些维基百科页面上针对UTF-8UTF-16UTF-32的编码就可以了。

原理很简单-根据一个UTF规范遍历输入并组装一个32位Unicode代码点,然后根据另一个规范发出代码点。各个代码点不需要转换,这是任何其他字符编码都需要的;这就是为什么这是一个简单的问题。

下面是wchar_t到UTF8转换的快速实现,反之亦然。它假设输入已经被正确编码--“垃圾输入,垃圾输出”这句老话适用于这里。我认为验证编码最好作为一个单独的步骤来完成。

代码语言:javascript
复制
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输入,原因很简单,因为从d800dfff的范围都是无效的代码点;它们表明您正在对UTF-16进行解码。如果你知道wchar_t是32位的,那么你可以删除一些代码来优化函数。

代码语言:javascript
复制
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在编译时是已知的,因此任何像样的编译器都会识别死代码并将其删除。

票数 25
EN

Stack Overflow用户

发布于 2008-09-29 14:42:31

Stack Overflow用户

发布于 2008-09-29 13:36:26

您可以从Boost serialization library中提取utf8_codecvt_facet

他们的用法示例:

代码语言:javascript
复制
  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.hpputf8_codecvt_facet.cpp文件。

票数 23
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/148403

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档