Как получить C ++ std :: string из байтов Little-Endian UTF-16 - PullRequest
1 голос
/ 08 ноября 2019

У меня есть устройство стороннего производителя, которое связывается с моей коробкой Linux по проприетарному протоколу связи, который плохо документирован. Некоторые пакеты передают «строки», которые после прочтения этой статьи Joel On Software выглядят в кодировке 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_t4 байта. У меня, однако, есть одна вещь, которая заключается в том, что мой Linux-пакет также Little-Endian. Поэтому я считаю, что мне нужно использовать что-то вроде std::codecvt_utf8_utf16<char16_t>. Однако даже после прочтения документации я не могу понять, как на самом деле перейти от unsigned char[] к std::string. Может кто-нибудь помочь, пожалуйста?

Ответы [ 2 ]

1 голос
/ 12 ноября 2019

Для полноты, вот самое простое преобразование на основе 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);
  }
}
1 голос
/ 08 ноября 2019

Если вы хотите использовать 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);
...