1

がありますstd::stringが、データはUTF-16でエンコードされているとします。データをまったく変更せず
に、そのデータをにコピーするにはどうすればよいですか?std::wstring

std::wstringまた、オンラインでテキストファイルを取得し、Content-Typeヘッダーフィールドをチェックしてエンコードを決定しているため、使用することはできません。しかしstd::string、データを受信するために使用します。

4

4 に答える 4

2
std::wstring PackUTF16(const std::string & input)
{
    if (input.size() % 2 != 0)
        throw std::invalid_argument("input length must be even");
    std::wstring result(input.size() / 2, 0);
    for (int i = 0;  i < result.size();  ++i)
    {
        result[i] = (input[2*i+1] & 0xff) << 8 | (input[2*i] & 0xff); // for little endian
        //result[i] = (input[2*i] & 0xff) << 8 | (input[2*i+1] & 0xff); // for big endian
    }
    return result;
}
于 2012-04-20T14:29:41.213 に答える
1

最初にBOM(Byte Order Mark)がある場合は、それをチェックしてバイト順序を決定します。それ以外の場合は、バイト順序がわかっている場合、つまり、最下位または最上位のバイトが最初に来る場合に最適です。バイト順序がわからず、BOMがない場合は、一方または両方を試して、統計的検定を適用するか、Human Decision Maker(HDM)を関与させる必要があります。

このリトルエンディアンのバイトオーダー、つまり最下位バイトが最初であるとしましょう。

次に、バイトの各ペアについて、たとえば

w.push_back( (UnsignedChar( s[2*i + 1] ) << 8u) | UnsignedChar( s[2*i] ) );

ここwstd::wstringiはワイド文字のインデックス< s.length()/2UnsignedCharはの、typedefはデータを保持し、8はバイトあたりのビット数です。つまり、ヘッダーから8であると想定または静的にアサートする必要があります。unsigned charsstd::stringCHAR_BITS<limits.h>

于 2012-04-20T14:27:52.353 に答える
1

これを試してください:

static inline std::wstring charToWide(const std::string & s_in)
{
    const char * cs = s_in.c_str();
    size_t aSize;
    if( ::mbsrtowcs_s(&aSize, NULL, 0, &cs, 0, NULL) != 0)
    {
      throw std::exception("Cannot convert string");
    }  
    std::vector<wchar_t> aBuffer(aSize);
    size_t aSizeSec;
    if (::mbstowcs_s(&aSizeSec, &aBuffer[0], aSize, cs, aSize) != 0)
    {
      throw std::exception("Cannot convert string");
    } 
    return std::wstring(&aBuffer[0], aSize - 1);
}
于 2012-04-20T14:28:46.620 に答える
0

つまり、UTF-16 でエンコードされた文字列を表す一連のバイトをstd::string. おそらく、UTF-16 を表すバイトを逆シリアル化するようなことを行っており、逆シリアル化するバイトを取得するための API は std::string を指定しています。それが最良の設計だとは思いませんが、バイトを float などに変換する場合と同じように、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

注意事項:

  • このキャストでは、wchar_t が 16 ビットであると想定していますが、ほとんどのプラットフォームでは 32 ビットの wchar_t が使用されています。
  • 有用であるためには、API が wchar_t 文字列を UTF-16 として扱うことができる必要があります。これは、wchar_t* のプラットフォーム指定エンコーディングであるため、または API がその規則に従っているためです。
  • このキャストは、データがマシンのエンディアンと一致することを前提としています。それ以外の場合は、wstring 内の各 UTF-16 コード単位を交換する必要があります。UTF-16 エンコーディング スキームでは、最初のバイトが 0xFF0xFE または 0xFE0xFF でなく、より高いレベルのプロトコルがない場合、UTF-16 エンコーディングはビッグ エンディアン エンディアン エンコーディングを使用します。
  • std::begin()、std::end()、および string::data() は C++11 です

* UTF-16 は、wchar_t エンコーディングに関する C++ 言語の要件を実際には満たしていませんが、一部のプラットフォームでは関係なく使用されています。これにより、コードポイントを処理するはずの一部の標準 API で問題が発生しますが、単に UTF-16 コード単位を表す wchar_t がプラットフォームのすべてのコードポイントを表すことができないため、処理できません。


これは、プラットフォーム固有の詳細に依存せず、wchar_t が UTF-16 コード単位を保持するのに十分な大きさであること、および各 char が UTF-16 コード単位の正確に 8 ビットを保持することだけを必要とする実装です。ただし、実際には 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";
}
于 2012-04-20T14:50:49.130 に答える