Frage

Betrachten Sie den folgenden Code:

#include <string>
#include <fstream>
#include <iomanip>

int main() {
    std::string s = "\xe2\x82\xac\u20ac";
    std::ofstream out("test.txt");
    out << s.length() << ":" << s << std::endl;
    out << std::endl;
    out.close();
}

Unter GCC 4.8 unter Linux (Ubuntu 14.04) die Datei test.txt enthält dies:

6:€€

Unter Visual C ++ 2013 unter Windows enthält es Folgendes:

4:€\x80

(Mit '\ x80' meine ich das einzelne 8-Bit-Zeichen 0x80).

Ich war völlig unfähig, einen der Compiler dazu zu bringen, a auszugeben zeichen mit std::wstring.

Zwei Fragen:

  • Was genau macht der Microsoft-Compiler mit dem char* wörtlich?Es tut offensichtlich etwas, um es zu kodieren, aber was ist nicht klar.
  • Was ist der richtige Weg, um den obigen Code mit umzuschreiben std::wstring und std::wofstream damit es zwei ausgibt charaktere?
War es hilfreich?

Lösung

Dies liegt daran, dass Sie verwenden \u20ac dies ist ein Unicode-Zeichenliteral in einer ASCII-Zeichenfolge.

MSVC codiert "\xe2\x82\xac\u20ac" als 0xe2, 0x82, 0xac, 0x80, welches sind 4 schmale Zeichen.Es kodiert im Wesentlichen \u20ac als 0x80, weil es das Euro-Zeichen auf den Standard abbildet 1252 codepage

GCC konvertiert das Unicode-Literal /u20ac zur 3-Byte-UTF-8-Sequenz 0xe2, 0x82, 0xac die resultierende Zeichenfolge endet also als 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac.

Wenn Sie verwenden std::wstring = L"\xe2\x82\xac\u20ac" es wird von MSVC als codiert 0xe2, 0x00, 0x82, 0x00, 0xac, 0x00, 0xac, 0x20 das sind 4 breite Zeichen, aber da Sie ein von Hand erstelltes UTF-8 mit einem UTF-16 mischen, ergibt die resultierende Zeichenfolge wenig Sinn.Wenn Sie ein std::wstring = L"\u20ac\u20ac" sie erhalten erwartungsgemäß 2 Unicode-Zeichen in einer breiten Zeichenfolge.

Das nächste Problem ist, dass MSVCS ofstream und wofstream immer in ANSI / ASCII schreiben.Um es in UTF-8 schreiben zu lassen, sollten Sie verwenden <codecvt> (VS 2010 oder später):

#include <string>
#include <fstream>
#include <iomanip>
#include <codecvt>

int main()
{
    std::wstring s = L"\u20ac\u20ac";

    std::wofstream out("test.txt");
    std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>);
    out.imbue(loc);

    out << s.length() << L":" << s << std::endl;
    out << std::endl;
    out.close();
}

und UTF-16 (oder genauer UTF-16LE) zu schreiben:

#include <string>
#include <fstream>
#include <iomanip>
#include <codecvt>

int main()
{
    std::wstring s = L"\u20ac\u20ac";

    std::wofstream out("test.txt", std::ios::binary );
    std::locale loc(std::locale::classic(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>);
    out.imbue(loc);

    out << s.length() << L":" << s << L"\r\n";
    out << L"\r\n";
    out.close();
}

Beachten:Bei UTF-16 müssen Sie einen Binärmodus anstelle eines Textmodus verwenden, um Beschädigungen zu vermeiden, daher können wir nicht verwenden std::endl und müssen verwenden L"\r\n" um das korrekte Verhalten der Zeilenende-Textdatei zu erhalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top