したがって、UTF-16でエンコードされた文字列を表す一連のバイトをstd::string
にスタックしました。おそらく、あなたはUTF-16を表すバイトをデシリアライズしたり、デシリアライズされるバイトを取得するためのAPIはstd :: stringを指定したりしているようです。私はそれが最高のデザインだとは思っていませんが、バイトを浮動小数点に変換する場合と同じようにwstringに変換して処理します。バイトのバッファを検証し、それをキャスト:心に留めておくべき
char c[] = "\0a\0b\xd8\x3d\xdc\x7f";
std::string buf(std::begin(c),std::end(c));
assert(0==buf.size()%2);
std::wstring utf16(reinterpret_cast<wchar_t const *>(buf.data()),buf.size()/sizeof(wchar_t));
// also validate that each code unit is legal, and that there are no isolated surrogates
もの:
- このキャストは、ほとんどのプラットフォームは32ビットのwchar_tを使用するのに対し、wchar_t型は、16ビットであることを前提としています。
- APIがwchar_t *のプラットフォームで指定されたエンコーディングであるか、またはAPIがその規約に従うだけなので、あなたのAPIは、wchar_t文字列をUTF-16として扱うことができるようにする必要があります。
- このキャストは、データがマシンのエンディアンと一致していることを前提としています。それ以外の場合は、wstringの各UTF-16コードユニットをスワップする必要があります。 UTF-16エンコーディング方式では、最初のバイトが0xFF0xFEまたは0xFE0xFFでなく、上位プロトコルが存在しない場合、UTF-16エンコーディングはビッグエンディアンエンコーディングを使用します。
- のstd ::()を開始、のstd :: end()は、文字列::データ()C++ 11
* UTF-16が実際にC++言語の要件を満たしていないされていますwchar_tエンコーディングでは、いくつかのプラットフォームがそれを使用しています。これは、コードポイントを処理するはずのいくつかの標準APIに問題を引き起こしますが、UTF-16コードユニットを表すwchar_tはすべてのプラットフォームのコードポイントを表すことができないからです。
ここでは、プラットフォーム固有の詳細に依存しない実装だとそれがUTF-16コード単位を保持し、各文字はUTF-16ののちょうど8ビットを保持するのに十分な大きさwchar_tのより多くの何も必要ありませんコード単位。 UTF-16データは実際には検証されません。
#include <string>
#include <cassert>
#include <iterator>
#include <algorithm>
#include <iostream>
enum class endian {
big,little,unknown
};
std::wstring deserialize_utf16be(std::string const &s) {
assert(0==s.size()%2);
std::wstring ws;
for(size_t i=0;i<s.size();++i)
if(i%2)
ws.back() = ws.back() | ((unsigned char)s[i] & 0xFF);
else
ws.push_back(((unsigned char)s[i] & 0xFF) << 8);
return ws;
}
std::wstring deserialize_utf16le(std::string const &s) {
assert(0==s.size()%2);
std::wstring ws;
for(size_t i=0;i<s.size();++i)
if(i%2)
ws.back() = ws.back() | (((unsigned char)s[i] & 0xFF) << 8);
else
ws.push_back((unsigned char)s[i] & 0xFF);
return ws;
}
std::wstring deserialize_utf16(std::string s, endian e=endian::unknown) {
static_assert(std::numeric_limits<wchar_t>::max() >= 0xFFFF,"wchar_t must be large enough to hold UTF-16 code units");
static_assert(CHAR_BIT>=8,"char must hold 8 bits of UTF-16 code units");
assert(0==s.size()%2);
if(endian::big == e)
return deserialize_utf16be(s);
if(endian::little == e)
return deserialize_utf16le(s);
if(2<=s.size() && ((unsigned char)s[0])==0xFF && ((unsigned char)s[1])==0xFE)
return deserialize_utf16le(s.substr(2));
if(2<=s.size() && ((unsigned char)s[0])==0xfe && ((unsigned char)s[1])==0xff)
return deserialize_utf16be(s.substr(2));
return deserialize_utf16be(s);
}
int main() {
char c[] = "\xFF\xFE\x61\0b\0\x3d\xd8\x7f\xdc";
std::string buf(std::begin(c),std::end(c)-1);
std::wstring utf16 = deserialize_utf16(buf);
std::cout << std::hex;
std::copy(begin(utf16),end(utf16),std::ostream_iterator<int>(std::cout," "));
std::cout << "\n";
}
あり、より良い方法かもしれませんが、あなたはCスタイルの文字列を通してそれを行うと、C++に戻って変換することができます:http://www.cplusplus.com/reference/clibrary/cstdlib/mbstowcs/ – chris