2008-09-28 8 views
12

Ich verwende TinyXML zum Parsen/Erstellen von XML-Dateien. Nach the documentation unterstützt diese Bibliothek Multibyte-Zeichensätze über UTF-8. So weit, so gut, denke ich. Aber die einzige API, die die Bibliothek bereitstellt (zum Abrufen/Festlegen von Elementnamen, Attributnamen und -werten, ... alles, wo eine Zeichenfolge verwendet wird), ist über std::string oder const char*. Das hat Zweifel an meinem Verständnis von Multibyte-Zeichensatz-Unterstützung. Wie kann eine Zeichenfolge, die nur 8-Bit-Zeichen unterstützt, ein 16-Bit-Zeichen enthalten (es sei denn, sie verwendet eine Codepage, die den Anspruch "Unicode unterstützt" negiert)? Ich verstehe, dass Sie theoretisch einen 16-Bit Codepunkt nehmen und ihn über 2 Zeichen in einem std::string teilen könnten, aber das würde den std::string nicht in einen 'Unicode'-String umwandeln, würde es für die meisten Zwecke ungültig machen und würde vielleicht versehentlich arbeiten, wenn sie in eine Datei geschrieben und von einem anderen Programm eingelesen werden.Wie funktioniert die UTF-8-Unterstützung von TinyXML?

Also, kann mir jemand erklären, wie eine Bibliothek eine '8-Bit-Schnittstelle' (std::string oder const char*) anbieten kann und trotzdem Unicode-Strings unterstützt?

(Ich habe hier wahrscheinlich ein wenig Unicode-Terminologie durcheinandergebracht; tut mir leid wegen der Verwirrung, die daraus entsteht).

Antwort

8

Zuerst wird utf-8 in const char * Strings gespeichert, wie @quinmars sagt. Und es ist nicht nur eine Obermenge von 7-Bit-ASCII (Codepunkte < = 127 immer in einem einzigen Byte als sie selbst codiert), ist es auch vorsichtig, dass Bytes mit diesen Werten nie als Teil der Codierung der Multibyte-Werte für Codepunkte verwendet werden > = 128. Wenn Sie also ein Byte == 44 sehen, handelt es sich um ein '<'-Zeichen usw. Alle Metachars in XML sind in 7-Bit-ASCII. So kann man einfach das XML analysieren, Strings brechen, wo die Metachars sagen, die Fragmente (möglicherweise einschließlich Nicht-ASCII-Zeichen) in eine char * oder std :: string kleben, und die zurückgegebenen Fragmente bleiben gültige UTF-8 Strings, obwohl die Parser kannte UTF-8 nicht genau.

Weiter (nicht XML-spezifisch, aber eher clever), funktionieren auch komplexere Dinge einfach nur (tm). Wenn Sie beispielsweise UTF-8 lexikografisch nach Bytes sortieren, erhalten Sie die gleiche Antwort wie die lexikografische Sortierung nach Codepunkten, obwohl die Anzahl der verwendeten Bytes variiert, da die Präfix-Bytes den längeren (und damit höherwertigen) Code enthalten Punkte sind numerisch größer als die für kleinere Werte).

+0

Ok danke, es wird klarer, aber dann - mit std :: string, um UTF-8 Daten auf diese Weise darzustellen, ist das nicht semantisch falsch? Sie können sich nie auf den Inhalt dieser Zeichenfolge verlassen - es wird nicht einmal möglich sein zu wissen, wie lange es ist! (in Zeichenlänge). – Roel

+0

Und selbst für die Version const char * müssen Sie immer noch eine andere Bibliothek verwenden, um zuverlässig mit der Zeichenfolge zu arbeiten. – Roel

+2

Mehr undefiniert als falsch. Die Methoden von std :: string (Verkettung, Iterator-Slicing, find_ *, usw.) funktionieren immer noch. length() wird sowieso nur als == size() definiert. Es gibt eine neue Voraussetzung dafür, dass Offsets an einer Char-Grenze liegen. Wenn std :: string irgendwelche Versprechungen bezüglich der Kodierung machen würde, wäre es falsch, tut es aber nicht. – puetzk

2

UTF-8 ist mit 7-Bit-ASCII-Code kompatibel. Wenn der Wert eines Bytes größer als 127 ist, bedeutet dies, dass ein Multibyte-Zeichen beginnt. Abhängig vom Wert des ersten Bytes können Sie sehen, wie viele Bytes das Zeichen braucht, das können 2-4 Bytes einschließlich des ersten Bytes sein (technisch sind auch 5 oder 6 möglich, aber sie sind ungültig utf-8). Hier ist eine gute Quelle über UTF-8: UTF-8 and Unicode FAQ, auch die Wiki-Seite für utf8 ist sehr informativ. Da UTF-8 char-basiert und 0-terminiert ist, können Sie die Standard-String-Funktionen für die meisten Dinge verwenden. Die einzige wichtige Sache ist, dass die Anzahl der Zeichen von der Anzahl der Bytes abweichen kann. Funktionen wie strlen() geben die Anzahl der Bytes zurück, aber nicht unbedingt die Anzahl der Zeichen.

0

Durch Verwendung von 1 bis 4 Zeichen, um einen Unicode-Codepunkt zu codieren.