18


5

移植可能にstd :: wstringをファイルに書き込む方法は?

そのように宣言された `wstring`があります:

// random wstring
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

[line-through]*The literal would be UTF-8 encoded, because my source ファイルは*です

[編集:Mark Ransomによると、これは必ずしもそうではなく、コンパイラが使用するエンコーディングを決定します。代わりに、この文字列を、たとえば UTF-8]

私はこれをファイル読み取りに取り込みたいと思います(テキストエディタが正しいエンコーディングに設定されている場合)

abcàdëefŸg€hhhhhhhµa

しかし、「ofstream」はあまり協調的ではなく(「wstring」パラメーターの取得を拒否します)、「wofstream」はロケールとエンコード設定を知る必要があると思われます。 このバイトのセットを出力したいだけです。 通常、どのようにこれを行いますか?

編集:クロスプラットフォームでなければならず、エンコーディングがUTF-8であることに依存してはいけません。 私はたまたま「wstring」に一連のバイトを保存していて、それらを出力したいと思っています。 UTF-16、またはプレーンASCIIになります。

9 Answer


28


`std

wstring`には` std :: wofstream`が必要です

std::wofstream f(L"C:\\some file.txt");
f << str;
f.close();


14


`std

wstring`はUTF-16やUTF-32のようなもので、UTF-8ではありません。 UTF-8の場合は、おそらく std :: string`を使用し、 std :: cout`を介して書き出すだけです。 ちょうどFWIW、C ++ 0xにはUnicodeリテラルがあり、このような状況を明確にするのに役立ちます。


7


ファイルをバイナリとして書きませんか。 ofstreamをstd

ios :: binary設定で使用するだけです。 エディターはそれを解釈できるはずです。 最初にUnicodeフラグ0xFEFFを忘れないでください。 ライブラリで書く方が良いかもしれません。次のいずれかを試してください。


4


C ++には、出力時またはファイル書き込み時にワイド文字からローカライズされた文字への変換を実行する手段があります。 https://stackoverflow.com/questions/4018384/stl-and-utf-8-file-input-output-how-to-do-it/4025951#4025951 [使用]その目的のためにcodecvtファセット。

標準のhttp://stdcxx.apache.org/doc/stdlibref/codecvt-byname.html[std::codecvt_byname]、または非標準codecvt_facet https://stackoverflow.com/questions/2971386/how-を使用できます。 do-i-write-a-stdcodecvt-facet / 2987731#2987731 [実装]。

#include
using namespace std;
typedef codecvt_facet Cvt;
locale utf8locale(locale(), new codecvt_byname ("en_US.UTF-8"));
wcout.imbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

一部のプラットフォームでは、codecvt_bynameはシステムにインストールされているロケールに対してのみ変換を発行できることに注意してください。 したがって、「utf8 codecvt」のstackoverflowを検索し、リストされているカスタムcodecvt実装の多くのリファレンから選択することをお勧めします。

編集:OPは文字列がすでにエンコードされていると述べているので、彼がすべきことは、コードのすべてのトークンからプレフィックスLと「w」を削除することです。


2


http://mariusbancila.ro/blog/2008/10/20/writing-utf-8-files-in-c/ [こちら]で動作する(Windows固有の)ソリューションがあります。 基本的に、 wstring`をUTF-8コードページに変換してから ofstream`を使用します。

#include < windows.h >

std::string to_utf8(const wchar_t* buffer, int len)
{
        int nChars = ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                NULL,
                0,
                NULL,
                NULL);
        if (nChars == 0) return "";

        string newbuffer;
        newbuffer.resize(nChars) ;
        ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                const_cast< char* >(newbuffer.c_str()),
                nChars,
                NULL,
                NULL);

        return newbuffer;
}

std::string to_utf8(const std::wstring& str)
{
        return to_utf8(str.c_str(), (int)str.size());
}

int main()
{
        std::ofstream testFile;

        testFile.open("demo.xml", std::ios::out | std::ios::binary);

        std::wstring text =
                L"< ?xml version=\"1.0\" encoding=\"UTF-8\"? >\n"
                L"< root description=\"this is a naïve example\" >\n< /root >";

        std::string outtext = to_utf8(text);

        testFile << outtext;

        testFile.close();

        return 0;
}


0


ワイドストリームはchar *変数のみを出力するため、 `c_str()`メンバー関数を使用して `std

wstring`を変換し、ファイルに出力することをお勧めします。 その後、おそらく動作するはずです?


0


しばらく前に同じ問題が発生し、ブログで見つけた解決策を書き留めました。 特に関数 `wstring_to_utf8`で、それが役立つかどうかを確認することをお勧めします。


0


移植可能なコードを作成する場合は、UTF-8エンコードされたソースファイルを使用しないでください。 ごめんなさい。

  std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

(これが実際に標準を傷つけるかどうかはわかりませんが、そうだと思います。 しかし、たとえ安全であっても、そうすべきではありません。)

はい、純粋に `std

ostream`を使用しても機能しません。 `wstring`をUTF-8に変換する方法はたくさんあります。 私のお気に入りは、http://site.icu-project.org/ [Unicodeの国際コンポーネント] *を使用することです。 それは大きなライブラリですが、素晴らしいです。 あなたは、将来必要になるかもしれない多くのエキストラと物を手に入れます。


0


さまざまな文字エンコーディングで作業した経験から、ロード時と保存時のみUTF-8を扱うことをお勧めします。 UTF-8で内部表現を保存しようとすると、1文字から1バイトまでの任意の文字になる可能性があるため、苦痛の世界に陥ります。 したがって、strlenのような単純な操作では、割り当てられたバッファーではなく、lenを決定するためにすべてのバイトを調べる必要があります(ただし、charシーケンスの最初のバイトを調べることで最適化できますが、 00..7fはシングルバイト文字、c2..dfは2バイト文字などを示します)。

UTF-16を意味し、Windowsではwchar_tが2バイトに固定されている場合、人々は「Unicode文字列」と呼ぶことがよくあります。 Windowsでは、wchar_tは単純だと思います。

typedef SHORT wchar_t;

完全なUTF-32 4バイト表現はめったに必要とされず、非常に無駄が多くなります。ここでは、Unicode Standard(5.0)がそれについて述べています。

「平均して、すべてのUTF-16の99%以上が単一のコード単位を使用して表現されています…​ UTF-16は、コンパクトなサイズと、BMPの外側の偶発的な文字を処理する機能との適切な組み合わせを提供します。

要するに、内部表現としてwhcar_tを使用し、ロードおよび保存時に変換を行います(必要な場合を除き、完全なUnicodeについて心配する必要はありません)。

実際の変換の実行に関しては、ICUプロジェクトをご覧ください。