3 Stimmen

wchar_t ist in Visual Studio 2 Bytes groß und speichert UTF-16. Wie arbeiten Unicode-fähige Anwendungen mit Zeichen über U+FFFF?

Wir planen in unserem Unternehmen, unsere Anwendung Unicode-fähig zu machen, und wir analysieren, welche Probleme dabei auftreten werden.

Unsere Anwendung wird zum Beispiel stark auf die Länge von Zeichenketten angewiesen sein, und wir würden gerne die wchar_t als Basiszeichenklasse.

Das Problem tritt auf, wenn es sich um Zeichen handelt, die in UTF-16 in 2 Einheiten von 16 Bit gespeichert werden müssen, nämlich Zeichen oberhalb von U+10000.

Einfaches Beispiel:

Ich habe die UTF-8 Zeichenfolge "" (Unicode-Zeichen U+87C2, in UTF-8: E8 9F 82)

Ich habe also den folgenden Code eingegeben:

const unsigned char my_utf8_string[] = { 0xe8, 0x9f, 0x82, 0x00 };

// compute size of wchar_t buffer.
int nb_chars = ::MultiByteToWideChar(CP_UTF8,                                  // input is UTF8
                                     0,                                        // no flags
                                     reinterpret_cast<char *>(my_utf8_string), // input string (no worries about signedness)
                                     -1,                                       // input is zero-terminated
                                     NULL,                                     // no output this time
                                     0);                                       // need the necessary buffer size

// allocate
wchar_t *my_utf16_string = new wchar_t[nb_chars];

// convert
nb_chars = ::MultiByteToWideChar(CP_UTF8,
                                 0,
                                 reinterpret_cast<char *>(my_utf8_string),
                                 -1,
                                 my_widechar_string, // output buffer
                                 nb_chars);          // allocated size

Okay, das funktioniert, es werden zweimal 16 Bit zugewiesen, und mein Puffer von wchar_t enthält { 0x87c2, 0x0000 }. Wenn ich es innerhalb eines std::wstring und berechne die Größe, erhalte ich 1.

Nehmen wir nun das Zeichen (U+104A2) als Eingabe in UTF-8: F0 90 92 A2.

Diesmal wird Platz für drei wchar_t reserviert und std::wstring::size liefert 2 auch wenn ich der Meinung bin, dass Ich habe nur ein Zeichen .

Dies ist problematisch. Nehmen wir an, dass wir Daten in UTF-8 erhalten. Wir können Unicode-Zeichen zählen, indem wir einfach die Bytes nicht zählen, die gleichbedeutend sind mit 10xxxxxx . Wir möchten diese Daten in ein Array von wchar_t um damit zu arbeiten. Wenn wir einfach die Anzahl der Zeichen plus eins zuweisen, könnte es sicher sein... bis jemand ein Zeichen über U+FFFF verwendet. Dann ist unser Puffer zu kurz und unsere Anwendung stürzt ab.

Also werden Funktionen, die Zeichen in einer Zeichenkette zählen, bei derselben Zeichenkette, die auf unterschiedliche Weise kodiert ist, unterschiedliche Werte zurückgeben?

Wie werden Anwendungen, die mit Unicode-Zeichenfolgen arbeiten, so gestaltet, dass diese Art von Ärgernissen vermieden wird?

Ich danke Ihnen für Ihre Antworten.

7voto

Martin v. Löwis Punkte 120025

Sie müssen akzeptieren, dass std::wstring::size no geben Sie die Anzahl der Zeichen an. Stattdessen gibt es die Anzahl der Codeeinheiten an. Bei 16-Bit-Codeeinheiten wird ermittelt, wie viele davon in der Zeichenkette enthalten sind. Die Berechnung der Anzahl der Unicode-Zeichen würde eine Schleife über die Zeichenkette erfordern. Das ist nicht mehr lästig, wenn Sie es akzeptieren.

Was das Zählen von Zeichen in UTF-8 angeht: tun Sie es nicht. Stattdessen ist der Code, den Sie gepostet haben, in Ordnung: Der einmalige Aufruf von MultiByteToWideChar sagt Ihnen, wie viele Codeeinheiten Sie benötigen, und Sie weisen dann die richtige Anzahl zu - sei es für BMP-Zeichen oder zusätzliche Ebenen. Wenn Sie unbedingt Ihre eigenen Zählroutinen schreiben wollen, sollten Sie zwei davon haben: eine, die Zeichen zählt, und eine, die 16-Bit-Codeeinheiten zählt. Wenn das Führungsbyte 11110xxx ist, müssen Sie zwei Codeeinheiten zählen.

3voto

Nemanja Trifunovic Punkte 23869

Ich schlage vor, Sie lesen die folgenden FAQ auf der offiziellen Unicode-Website: http://www.unicode.org/faq//utf_bom.html

Grundsätzlich ist es wichtig, zwischen Codeeinheiten, Codepunkten und Zeichen zu unterscheiden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X