【问题标题】:How to get C++ std::string from Little-Endian UTF-16 encoded bytes如何从 Little-Endian UTF-16 编码字节获取 C++ std::string
【发布时间】:2019-11-08 14:03:11
【问题描述】:

我有一个第 3 方设备,它通过没有很好记录的专有通信协议与我的 Linux 机器通信。一些数据包传送“字符串”,在读取this Joel On Software article 后,似乎采用 UTF16 Little-Endian 编码。换句话说,在收到此类数据包后,我的 Linux 机器上的内容类似于

// The string "Out"
unsigned char data1[] = {0x4f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00};

// The string "°F"
unsigned char data2[] = {0xb0, 0x00, 0x46, 0x00, 0x00, 0x00};

据我了解,我不能将它们视为 std::wstring,因为在 Linux 上 wchar_t 是 4 个字节。然而,我确实有一件事情适合我,因为我的 Linux 机器也是 Little-Endian。所以,我相信我需要使用std::codecvt_utf8_utf16<char16_t> 之类的东西。然而,即使在阅读the documentation 之后,我也无法弄清楚如何从unsigned char[] 实际转到std::string。有人可以帮忙吗?

【问题讨论】:

标签: c++ string utf-16 unicode-string


【解决方案1】:

如果您希望使用 std::codcvt(自 C++ 17 起已弃用),您可以包装 UTF-16 文本,然后在需要时将其转换为 UTF-8。

// simply cast raw data for constructor, since we known that char 
// is actually 'byte' array from network API
std::u16string u16_str( reinterpret_cast<const char16_t*>(data2) );

// UTF-16/char16_t to UTF-8
std::string u8_conv = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t>{}.to_bytes(u16_str);

【讨论】:

  • 感谢您提供答案!我不知道 std::codcvt 在 C++17 中已被弃用,这实际上是我正在使用的。在 C++17 中执行相同操作的正确方法是什么?
  • 似乎不再有标准库功能了.
  • @PaulGrinberg 这是一种不幸的情况,因为没有:stackoverflow.com/q/42946335/256138
【解决方案2】:

为了完整起见,这是我想出的最简单的基于iconv 的转换

#include <iconv.h>

auto iconv_eng = ::iconv_open("UTF-8", "UTF-16LE");
if (reinterpret_cast<::iconv_t>(-1) == iconv_eng)
{
  std::cerr << "Unable to create ICONV engine: " << strerror(errno) << std::endl;
}
else
{
  // src            a char * to utf16 bytes
  // src_size       the maximum number of bytes to convert
  // dest           a char * to utf8 bytes to generate
  // dest_size      the maximum number of bytes to write
  if (static_cast<std::size_t>(-1) == ::iconv(iconv_eng, &src, &src_size, &dest, &dest_size))
  {
    std::cerr << "Unable to convert from UTF16: " << strerror(errno) << std::endl;
  }
  else
  {
    std::string utf8_str(src);
    ::iconv_close(iconv_eng);
  }
}

【讨论】:

  • 您忘记了 UTF-8 目标内存缓冲区大小检测。 static std::size_t utf8_buff_size(const char16_t* ustr, std::size_t size) noexcept 在头文件中。
  • @VictorGubin - 我不确定我是否理解您的评论。你能澄清一下吗?作为一个可能的相关点,我的 utf16 字节以 NULL 结尾 - 也就是说,最后两个字节是 0x00 0x00
  • 您怎么知道 - 目标 UTF-8 缓冲区的大小(以字节为单位) (&amp;dest, &amp;dest_size)?如果它太小 iconv 将失败并出现“没有更多空间”错误。您可以简单地将 UTF-16 字符串长度乘以 2,同时当源字符串主要包含 latin1 例如单字节字符——你会浪费很多内存(50%)。所以最好的选择 - 计算目标缓冲区大小。
猜你喜欢
  • 2013-09-26
  • 1970-01-01
  • 2011-06-17
  • 2012-06-20
  • 2019-03-13
  • 2015-08-04
  • 2018-08-09
  • 1970-01-01
  • 2013-07-18
相关资源
最近更新 更多