2016-10-18 5 views
0

UTF-8でエンコードされた文字列をUTF-16でエンコードされたCStringWに変換する際に問題があります。大きなUTF-8エンコードされたchar *文字列をCStringW(UTF-16)に変換するには?

CStringW ConvertUTF8ToUTF16(__in const CHAR * pszTextUTF8) 
{ 
    _wsetlocale(LC_ALL, L"Korean"); 
    if ((pszTextUTF8 == NULL) || (*pszTextUTF8 == '\0')) 
    { 
     return L""; 
    } 
    const size_t cchUTF8Max = INT_MAX - 1; 
    size_t cchUTF8; 
    HRESULT hr = ::StringCbLengthA(pszTextUTF8, cchUTF8Max, &cchUTF8); 
    if (FAILED(hr)) 
    { 
     AtlThrow(hr); 
    } 
    ++cchUTF8; 
    int cbUTF8 = static_cast<int>(cchUTF8); 

    int cchUTF16 = ::MultiByteToWideChar(
     CP_UTF8, 
     MB_ERR_INVALID_CHARS, 
     pszTextUTF8, 
     -1, 
     NULL, 
     0 
     ); 

    CString strUTF16; 
    strUTF16.GetBufferSetLength(cbUTF8); 
    WCHAR * pszUTF16 = new WCHAR[cchUTF16]; 

    int result = ::MultiByteToWideChar(
     CP_UTF8, 
     0, 
     pszTextUTF8, 
     cbUTF8, 
     pszUTF16, 
     cchUTF16 
     ); 
    ATLASSERT(result != 0); 
    if (result == 0) 
    { 
     AtlThrowLastWin32(); 
    } 
    strUTF16.Format(_T("%s"), pszUTF16); 
    return strUTF16; 
} 

pszTextUTF8はUTF-8でのHTMファイルの内容です:

は、ここに私のソースコードです。 htmファイルのボリュームが500kb未満の場合、このコードはうまく機能します。 しかし、500kbのhtmファイルを変換すると(私が持っている648KBのhtmファイル) pszUTF16にはすべてのファイルの内容が含まれていますが、strUTF16はありません。 (約半分) ファイルオープンが間違っていないと思います。

strUTF16 m_pszDataにはどのように取得するのですか? strUTF16.Getbuffer();

+2

'CStringW strUTF16 = CA2W(pszTextUTF8、CP_UTF8)は'あなたのすべてです必要。まだ動作していない場合は、ファイルを読み込んでいる部分を表示してください。 UTF8ファイルを読むときは、ヌルターミネータのためのスペースを残して、最後のバイトを0にしてください。 –

+0

ありがとうございました。私は私の問題を解決しました。 MSビジュアルスタジオのテキストビジュアライザ効率の問題でした。私は変換したファイルCStringコンテンツとしてエクスポートしました。ファイルより完全な内容です!もう一度感謝します〜 – Kim

+0

@BarmakShemirani:それはそれに多くの思考を入れないで動作する直進的な解決策です。ただし、余分なコピーが生成され、最後の文字列の2倍のメモリが必要です。問題のコードは 'CStringW'オブジェクトを作成したいので、そのバッファに直接書き込んで、余分なバッファとコピー操作の両方を安全に行うことができます。 – IInspectable

答えて

1

問題のコードには、1-2行のコードごとに1つのバグがあります。ここで

は短い要約です:変換機能のグローバル設定を変更する

_wsetlocale(LC_ALL, L"Korean"); 

は予想外であり、それを呼び出すコードを中断します。どちらも必要ではありません。エンコード変換にロケールを使用していません。

HRESULT hr = ::StringCbLengthA(pszTextUTF8, cchUTF8Max, &cchUTF8); 

これは(documentationに従って)間違ったcchUTF8Max値を渡し、そしてバイト(対文字の数、すなわち、コード単位)の数をカウントします。それ以外にもコードユニットの数を知っている必要はありません(まあまあですが、これは別のバグです)。

int cbUTF8 = static_cast<int>(cchUTF8); 

それは接頭辞(CH aractersのC ountとは対照的に、B ytesのC ount)を修正するが、それはその何かのために後でそれを使用してからあなたを保存されません無関係の値を持つ。

strUTF16.GetBufferSetLength(cbUTF8); 

最終的にUTF-16エンコードされた文字を保持する文字列オブジェクトのサイズを変更します。しかし、正しい文字数を使用していません(以前の呼び出しではMultiByteToWideCharはその値を提供していました)。完全に無関係な値を選択します。バイトのUTF-8エンコードソース文字列の番号。

しかし、それだけで終わるわけではありません。そのコード行は、書き込む準備ができた内部バッファへのポインタもスローします。 ReleaseBufferに電話をかけなかった場合は、documentationを読むことに決めたので、当然の結果です。

WCHAR * pszUTF16 = new WCHAR[cchUTF16]; 

バグではありませんが、別のバッファ(今度は正しいサイズを渡します)を不必要に割り当てます。 GetBufferSetLengthへの前回の呼び出しでは、必要なサイズのバッファを既に割り当てています(間違っています)。それを使うだけで、メンバー関数のためです。おそらく機能のprintf家族に関連したアンチパターンある

strUTF16.Format(_T("%s"), pszUTF16); 

。これは、CopyChars(またはAppend)と書かれた複雑な方法です。

今では片付けだことを、ここではその機能(またはそれを行うには、少なくとも一つの方法)を書き込むための正しい方法は次のとおりです。

CStringW ConvertUTF8ToUTF16(__in const CHAR * pszTextUTF8) { 
    // Allocate return value immediately, so that (N)RVO can be applied 
    CStringW strUTF16; 
    if ((pszTextUTF8 == NULL) || (*pszTextUTF8 == '\0')) { 
     return strUTF16; 
    } 

    // Calculate the required destination buffer size 
    int cchUTF16 = ::MultiByteToWideChar(CP_UTF8, 
              MB_ERR_INVALID_CHARS, 
              pszTextUTF8, 
              -1, 
              nullptr, 
              0); 

    // Perform error checking 
    if (cchUTF16 == 0) { 
     throw std::runtime_error("MultiByteToWideChar failed."); 
    } 

    // Resize the output string size and use the pointer to the internal buffer 
    wchar_t* const pszUTF16 = strUTF16.GetBufferSetLength(cchUTF16); 

    // Perform conversion (return value ignored, since we just checked for success) 
    ::MultiByteToWideChar(CP_UTF8, 
          MB_ERR_INVALID_CHARS, // Use identical flags 
          pszTextUTF8, 
          -1, 
          pszUTF16, 
          cchUTF16); 

    // Perform required cleanup 
    strUTF16.ReleaseBuffer(); 

    // Return converted string 
    return strUTF16; 
} 
関連する問題