将 wstring 转换为 UTF-8 编码的字符串

Posted

技术标签:

【中文标题】将 wstring 转换为 UTF-8 编码的字符串【英文标题】:Convert wstring to string encoded in UTF-8 【发布时间】:2011-05-20 12:30:45 【问题描述】:

我需要在 wstring 和 string 之间进行转换。我发现,使用 codecvt facet 应该可以解决问题,但它似乎不适用于 utf-8 语言环境。

我的想法是,当我将 utf-8 编码文件读取为字符时,一个 utf-8 字符被读入两个普通字符(这就是 utf-8 的工作原理)。我想从我在代码中使用的库的 wstring 表示创建这个 utf-8 字符串。

有人知道怎么做吗?

我已经试过了:

  locale mylocale("cs_CZ.utf-8");
  mbstate_t mystate;

  wstring mywstring = L"čřžýáí";

  const codecvt<wchar_t,char,mbstate_t>& myfacet =
    use_facet<codecvt<wchar_t,char,mbstate_t> >(mylocale);

  codecvt<wchar_t,char,mbstate_t>::result myresult;  

  size_t length = mywstring.length();
  char* pstr= new char [length+1];

  const wchar_t* pwc;
  char* pc;

  // translate characters:
  myresult = myfacet.out (mystate,
      mywstring.c_str(), mywstring.c_str()+length+1, pwc,
      pstr, pstr+length+1, pc);

  if ( myresult == codecvt<wchar_t,char,mbstate_t>::ok )
   cout << "Translation successful: " << pstr << endl;
  else cout << "failed" << endl;
  return 0;

对于 cs_CZ.utf-8 语言环境返回“失败”并且对于 cs_CZ.iso8859-2 语言环境正常工作。

【问题讨论】:

看看这个链接:boost.org/doc/libs/1_42_0/libs/serialization/doc/codecvt.html 可能会有所帮助 "一个 utf-8 字符被读入两个普通字符(这是 utf-8 的工作原理)" 不,不是。 UTF-16(大部分)以这种方式工作,但一个 UTF-8 代码点由 1 到 4 个字节表示,一个“字符”可以由多个代码点组成。 ephimient - 是的 - 我知道,我只是写得不好:) 【参考方案1】:

下面的代码可能会对你有所帮助:)

#include <codecvt>
#include <string>

// convert UTF-8 string to wstring
std::wstring utf8_to_wstring (const std::string& str)

    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.from_bytes(str);


// convert wstring to UTF-8 string
std::string wstring_to_utf8 (const std::wstring& str)

    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.to_bytes(str);

【讨论】:

但不是在使用 libstdc++ 的 linux 上。 在上述工作的同时。我强烈建议研究 Unicode 库,例如 ICU 和 Boost.Locale。 它对任何std::wstring 都有效。这里的小测试:***.com/a/37531136/1802974 codecvt 自 C++17 起已弃用且没有替代品。 @AlexReinking cpp 参考并没有说 codecvt 已被弃用。虽然不推荐使用某些成员,但添加了一些新成员(例如,C++20 添加了std::codecvt&lt;char32_t, char8_t, std::mbstate_t&gt;)。 en.cppreference.com/w/cpp/locale/codecvt【参考方案2】:

你的平台是什么?请注意,Windows 不支持 UTF-8 语言环境,因此这可以解释您失败的原因。

要以依赖于平台的方式完成此操作,您可以在 Windows 上使用 MultiByteToWideChar/WideCharToMultiByte 在 Linux 上使用 iconv。您也许可以使用一些增强魔法以独立于平台的方式完成此操作,但我自己没有尝试过,因此无法添加此选项。

【讨论】:

【参考方案3】:

您可以使用 boost 的 utf_to_utf 转换器来获取 char 格式以存储在 std::string 中。

std::string myresult = boost::locale::conv::utf_to_utf<char>(my_wstring);

【讨论】:

【参考方案4】:

语言环境的作用是它提供有关外部编码的程序信息,但假设内部编码没有改变。如果你想输出 UTF-8,你需要从 wchar_t 而不是 char*

您可以将其作为原始数据(而非字符串)输出,如果系统区域设置为 UTF-8,则应正确解释它。

另外,当使用(w)cout/(w)cerr/(w)cin 时,您需要在流中注入语言环境。

【讨论】:

UTF-8 使用 8 位代码单元。 char(以及 signed charunsigned char)必须至少为 8 位。我相信您可能会想到 UTF-16、UTF-32、UCS2 或 UCS4。【参考方案5】:

Lexertl library 有一个迭代器可以让你这样做:

std::string str;
str.assign(
  lexertl::basic_utf8_out_iterator<std::wstring::const_iterator>(wstr.begin()),
  lexertl::basic_utf8_out_iterator<std::wstring::const_iterator>(wstr.end()));

【讨论】:

【参考方案6】:

C++ 不知道 Unicode。使用外部库,例如 ICU (UnicodeString class) 或 Qt (QString class),它们都支持 Unicode,包括 UTF-8。

【讨论】:

-1 不是真的,C++ 支持包含编码的语言环境(不幸的是,这在 Windows 上被 UTF-8 破坏了) 同意。 C++ 不保证 Unicode,或locale ("cs_CZ.utf-8"); 的存在。但是,如果您有一个具有该语言环境的系统,它会更好地工作。 自 C++11 起不再适用。 char16_t 专门用于 UTF-16,char32_t 专门用于 UTF-32; C++14 对此进行了扩展,要求 char 类型足够大以存储 256 个不同的值,特别适用于 UTF-8。 C++11 还添加了类codecvt_utf8codecvt_utf16codecvt_utf8_utf16,以及codecvt 的两个新特化(std::codecvt&lt;char16_t, char, std::mbstate_t&gt;std::codecvt&lt;char32_t, char, std::mbstate_t&gt;)。所以,C++ 现在正式支持 UTF-8、UTF-16、UTF-32、UCS2 和 UCS4。 codecvts 中:codecvt_utf8 在 UTF-8 和 UCS2/UCS4 之间转换,codecvt_utf16 在 UTF-16 和 UCS2/UCS4 之间转换,codecvt_utf8_utf16 在 UTF-8 之间转换和 UTF-16,codecvtchar16_t 特化也适用于 UTF-8 和 UTF-16,codecvtchar32_t 特化在 UTF-8 和 UTF-32 之间转换。还不能 100% 确定它们是如何工作的,实际上我今天才开始学习 Unicode 转换。

以上是关于将 wstring 转换为 UTF-8 编码的字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UTF-8 std::string 转换为 UTF-16 std::wstring?

c++字符编码转换

string和wstring相互转换

为啥我不能将带有破折号的字符串转换为 wstring?

C++ 使用最少的代码将字符串转换为 wstring 并返回

将字符串的编码格式转换为utf-8