2010-03-27 16 views
14

Ich arbeite an einem Englisch nur C++ - Programm für Windows, wo uns gesagt wurde "immer std :: wstring", aber es scheint, dass niemand im Team wirklich viel Verständnis darüber hat.Verwirrt über C++ 's st :: wstring, UTF-16, UTF-8 und Anzeige von Strings in einer Windows-GUI

Ich habe bereits die Frage mit dem Titel "std::wstring VS std::string gelesen. Es war sehr hilfreich, aber ich verstehe immer noch nicht, wie ich all diese Informationen auf mein Problem anwenden kann.

Das Programm, an dem ich gerade arbeite, zeigt Daten in einer Windows GUI an. Diese Daten werden als XML beibehalten. Wir wandeln dieses XML häufig mit XSLT in HTML oder XSL: FO für Berichtszwecke um.

Mein Gefühl basierend auf dem, was ich gelesen habe, ist, dass der HTML-Code als UTF-8 codiert werden sollte. Ich weiß sehr wenig über GUI-Entwicklung, aber das bisschen, was ich gelesen habe, deutet darauf hin, dass das GUI-Zeug alles auf UTF-16-codierten Strings basiert.

Ich versuche zu verstehen, wo dies mich verlässt. Nehmen wir an, wir entscheiden, dass alle unsere persistenten Daten UTF-8-kodiertes XML sein sollen. Bedeutet dies, dass ich, um persistente Daten in einer UI-Komponente anzuzeigen, wirklich eine Art von explizitem UTF-8-UTF-16-Transcodierungsprozess durchführen sollte?

Ich vermute, dass meine Erklärung Klarstellung verwenden könnte, also werde ich versuchen, das zur Verfügung zu stellen, wenn Sie irgendwelche Fragen haben.

Antwort

7

Windows ab NT4 basiert auf Unicode-codierten Zeichenfolgen, ja. Frühere Versionen basierten auf UCS-2, dem Vorgänger oder UTF-16, und unterstützen daher nicht alle Zeichen, die UTF-16 verwendet. Spätere Versionen basieren auf UTF-16. Nicht alle Betriebssysteme basieren jedoch auf UTF-16/UCS-2. * Nix-Systeme zum Beispiel basieren stattdessen auf UTF-8.

UTF-8 ist eine sehr gute Wahl für die dauerhafte Speicherung von Daten. Es ist eine universell unterstützte Kodierung in allen Unicode-Umgebungen und es ist eine gute Balance zwischen Datengröße und verlustfreier Datenkompatibilität.

Ja, Sie müssten das XML analysieren, die notwendigen Informationen daraus extrahieren und es in etwas dekodieren und transformieren, das die Benutzeroberfläche verwenden kann.

+3

Es ist nicht wirklich genau zu sagen, dass * nix auf UTF-8 basiert die Art, wie Windows auf UTF-16 basiert. Es basiert auf einer länderspezifischen Zeichencodierung (in der Windows-Terminologie ANSI). POSIX erfordert, dass bestimmte Zeichen (einschließlich NUL) in einem einzigen Byte dargestellt werden, so dass UTF-16 und UTF-32 nicht zulässig sind, aber UTF-8 ist. – dan04

3

Ein Vorteil für die Verwendung von std :: wstring unter Windows für GUI-bezogene Strings ist, dass intern alle Windows-API-Aufrufe UTF-16 verwenden und damit arbeiten. Wenn Sie jemals bemerkt haben, gibt es 2 Versionen aller Win32-API-Aufrufe, die Zeichenfolgenargumente verwenden. Zum Beispiel "MessageBoxA" und "MessageBoxW". Beide Definitionen existieren in und in der Tat können Sie rufen entweder Sie wollen, aber wenn mit Unicode-Unterstützung enthalten aktiviert ist, dann passiert folgendes:

#define MessageBox MessageBoxW 

Dann erhalten Sie in TCHAR und anderer Microsoft Tricks zu versuchen und machen Es ist einfacher, mit APIs zu arbeiten, die sowohl eine ANSI- als auch eine Unicode-Version haben. Kurz gesagt, Sie können entweder den Windows-Kernel auf Unicode-Basis aufrufen, aber Sie bezahlen die Kosten für die Konvertierung in Unicode für jeden String, der den Win32-API-Aufruf akzeptiert, wenn Sie die Wide-Char-Version nicht verwenden.

UTF-16 and Windows kernel use

4

std :: wstring ist technisch UCS-2: zwei Bytes für jedes Zeichen und die Codetabellen verwendet werden meist Karte zu Unicode-Format. Es ist wichtig zu verstehen, dass UCS-2 nicht dasselbe ist wie UTF-16! UTF-16 erlaubt "Ersatzpaare", um Zeichen darzustellen, die außerhalb des Zwei-Byte-Bereichs liegen, aber UCS-2 verwendet genau zwei Bytes für jedes Zeichen, Periode.

Die beste Regel für Ihre Situation ist das Umcodieren beim Lesen und Schreiben auf die Festplatte. Sobald es im Speicher ist, halten Sie es im UCS-2-Format. Windows-APIs lesen es so, als wäre es UTF-16 (was bedeutet, dass std :: wstring das Konzept von Ersatzpaaren nicht versteht, wenn Sie sie manuell erstellen (was nicht der Fall ist, wenn Ihre einzige Sprache ist) Englisch), Windows wird sie lesen).

Wann immer Sie heute Daten in oder aus Serialisierungsformaten (wie XML) lesen, müssen Sie wahrscheinlich Transcoding durchführen. Es ist eine unangenehme und sehr unglückliche Tatsache des Lebens, aber unvermeidlich, da Unicode eine Zeichencodierung mit variabler Breite ist und die meisten zeichenbasierten Operationen in C++ als Arrays ausgeführt werden, für die Sie konsistente Abstände benötigen.

Übergeordnete Frameworks wie .NET verdecken die meisten Details, aber hinter den Kulissen behandeln sie die Transcodierung auf dieselbe Weise: Daten mit variabler Breite in Strings mit fester Breite ändern, sie manipulieren, und dann, wenn sie für die Ausgabe benötigt werden, sie wieder in Kodierungen mit variabler Breite zu ändern.

+2

Was sagen, dass std :: wstring UCS-2 ist? std :: wstring verwenden Sie einfach wchar_t statt och char als Basis für die Zeichenfolge. Und wchar_t ist implementierungsabhängig. Aber ich denke, in den meisten modernen 32/64-Bit-Systemen wird es dasselbe wie char16_t sein. In dem würde Ether UCS-2 oder UTF-16 passen, da sie 16 Bit breit sind. – jpyllman

+2

Guter Punkt. std :: wstring ist technisch gesehen keine Zeichencodierung. Es sind nur zwei Byte breite Zeichen. Aber UTF-16 ist ** nicht ** 16 Bit breit! Es verwendet ein ** Minimum ** von 16 Bits, um ein Zeichen zu speichern, kann aber bis zu 32 Bits verwenden, wenn das Zeichen es erfordert! Dies hat zu einer Reihe von Pufferüberlauf-Angriffen auf Anwendungen geführt, die UTF-16-codierte Zeichenfolgen in Zeichen messen und dann fälschlicherweise (Zeichen + 1) * 2 Byte Speicher zuordnen und die Zeichenfolge blind kopieren! –

+0

@Dan Story: Und es kann noch schlimmer sein, wenn es kammende Charaktere gibt, mit denen man in einem einzigen Graphem umgehen kann. –

1

Selbst wenn Sie sagen, dass Sie nur Englisch in Ihren Daten haben, liegen Sie wahrscheinlich falsch. Da wir jetzt in einer globalen Welt sind, haben Namen/Adressen/etc fremde Zeichen. OK, ich weiß nicht, welche Art von Daten Sie haben, aber im Allgemeinen würde ich sagen, bauen Sie Ihre Anwendung zur Unterstützung von UNICODE sowohl zum Speichern von Daten als auch zum Anzeigen von Daten für den Benutzer. Dies würde vorschlagen, XML mit UTF-8 zum Speichern und UNICODE-Versionen von Windows-Aufrufen zu verwenden, wenn Sie GUI ausführen. Und da Windows GUI UTF-16 verwendet, wobei jedes Token 16-Bit ist, würde ich vorschlagen, die Daten in der Anwendung in einer 16-Bit breiten Zeichenfolge zu speichern. Und ich würde schätzen, dass Ihr Compiler für Windows std :: wstring als 16-Bit für genau diesen Zweck haben würde.

Also dann müssen Sie eine Menge Konvertierung zwischen UTF-16 und UTF-8 machen. Tun Sie das mit einer vorhandenen Bibliothek, wie zum Beispiel ICU.

+0

Fluch gibt es nichts falsch speichern von Daten in XML mit UTF-16. Aber ich würde UTF-8 trotzdem für eine einfachere Portabilität zwischen verschiedenen Systemen vorschlagen. – jpyllman

+2

UTF-8 ist sowieso fast immer eine bessere Wahl für XML, da die Vorherrschaft von Englisch als Computersprache bedeutet, dass die meisten Markup-Zeichen in den meisten XML-Dokumenten in den 8-Bit-Bereich der UTF-8-Codierung fallen , was zu erheblichen Platzeinsparungen führt. Dies gilt im Allgemeinen auch dann, wenn die Sprache des Dokuments * content * in einer nicht-englischen Sprache ist, die einen erweiterten Zeichensatz verwendet. –

+2

Und eigentlich könnte es sogar besser sein, std :: string im Programm zu verwenden und UTF-8 in ihnen zu speichern. Und dann konvertieren Sie nur zu UTF-16 für Windows, wenn Sie etwas anzeigen möchten. Arbeiten nur mit UTF-8 in jedem anderen Sinne. – jpyllman

5

AFAIK Wenn Sie mit std :: wstring unter Windows in C++ arbeiten und mit UTF-8 in Dateien speichern (was sich gut anhört), müssen Sie die Daten beim Schreiben in eine Datei in UTF-8 konvertieren, und konvertiert zurück in UTF-16 beim Lesen aus einer Datei. Überprüfen Sie diesen Link: Writing UTF-8 Files in C++.

Ich würde mit dem Visual Studio-Standard von Projekt bleiben -> Eigenschaften -> Konfigurationseigenschaften -> Allgemein -> Zeichensatz -> Unicode-Zeichensatz verwenden, verwenden Sie den Typ wchar_t (dh mit Std :: wstring) und nicht Verwenden Sie den TCHAR-Typ. (Z. B. würde ich nur die wcslen-Version von strlen und nicht _tcslen.)