web-dev-qa-db-ja.com

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

wstringが次のように宣言されています。

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

私のソースファイルはUTF-8でエンコードされているため、リテラルはUTF-8でエンコードされます。

[編集:Mark Ransomによると、これは必ずしも当てはまるわけではなく、コンパイラが使用するエンコーディングを決定します。代わりに、たとえばでエンコードされたファイルからこの文字列を読み取ったと仮定します。 UTF-8]

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

abcàdëefŸg€hhhhhhhµa

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

編集:クロスプラットフォームである必要があり、TF-8であるエンコーディングに依存しないでください。たまたまwstringにバイトのセットが格納されていて、それらを出力したいと思っています。それはUTF-16またはプレーンASCIIである可能性が非常に高いです。

18
Oystein

ファイルをバイナリとして書き込んでみませんか。 std :: ios :: binary設定でofstreamを使用するだけです。その場合、編集者はそれを解釈できるはずです。最初にUnicodeフラグ0xFEFFを忘れないでください。ライブラリを使用して作成する方がよい場合は、次のいずれかを試してください。

http://www.codeproject.com/KB/files/EZUTF.aspx

http://www.gnu.org/software/libiconv/

http://utfcpp.sourceforge.net/

7
inf.ig.sh

にとって std::wstring必要ですstd::wofstream

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

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

14
Jerry Coffin

C++には、出力またはファイル書き込み時にワイド文字からローカライズ文字への変換を実行する手段があります。 使用 その目的のためのcodecvtファセット。

標準 std :: codecvt_byname 、または非標準codecvt_facet implementation を使用できます。

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

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

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

4
Basilevs

あなたのために働くはずの(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;
}
2
Steve Townsend

ワイドストリームはchar *変数のみを出力するため、c_str()メンバー関数を使用してstd::wstringを変換し、それをファイルに出力してみてください。それならおそらくうまくいくはずですか?

0
user225312

ポータブルコードを記述したい場合は、not UTF-8でエンコードされたソースファイルを使用する必要があります。ごめんなさい。

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

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

はい、純粋にstd::ostreamを使用しても機能しません。 wstringをUTF-8に変換する方法はたくさんあります。私のお気に入りはthe International Components for Unicodeを使用することです。それは大きなライブラリですが、素晴らしいです。あなたはあなたが将来必要とするかもしれないたくさんのエキストラと物を手に入れます。

0
towi

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

http://pileborg.org/b2e/blog5.php/2010/06/13/unicode-utf-8-and-wchar_t

さまざまな文字エンコードを使用した私の経験から、ロード時にUTF-8のみを扱い、時間を節約することをお勧めします。 1文字は1バイトから4までの範囲である可能性があるため、内部表現をUTF-8に格納しようとすると、苦痛の世界に陥ります。したがって、strlenのような単純な操作では、すべてのバイトを調べてlenを決定する必要があります。割り当てられたバッファ(charシーケンスの最初のバイトを確認することで最適化できますが、たとえば00..7fは1バイトの文字、c2..dfは2バイトの文字などを示します)。

UTF-16を意味し、Windowsではwchar_tが固定2バイトである場合、「Unicode文字列」をよく参照します。 Windowsでは、wchar_tは単純に次のようになります。

typedef SHORT wchar_t;

完全なUTF-324バイト表現が必要になることはめったになく、非常に無駄です。ここでは、Unicode標準(5.0)で次のように述べています。

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

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

実際の変換の実行に関しては、ICUプロジェクト:

http://site.icu-project.org/

0
snowdude