C++ und Unicode
-
Hi. Ich möchte ein Chatprogramm schreiben, über das auch japanische Zeichen etc. genutzt werden können. Das Encoding kann ich also frei festlegen. (UTF-8 oder UTF-16?)
Ich weiß zwar theoretisch wie das funktioniert, aber nicht was genau ich dafür jetzt machen muss. Gibt es irgendwo ein Tutorial zu wstringstream, wstring, wchar_t, char16_t, ...? Muss ich da im Compiler noch etwas umstellen? Wie behandle ich Strings? Muss ich Ein/Ausgaben erst umwandeln? Alles irgendwie etwas verwirrend. Der Artikel hier im Forum über Unicode behandelt ja auch eher die Theorie. Zudem scheint er recht alt zu sein. Hat sich da mit C++11 was geändert?
-
kein japaner schrieb:
Hi. Ich möchte ein Chatprogramm schreiben, über das auch japanische Zeichen etc. genutzt werden können. Das Encoding kann ich also frei festlegen. Ich weiß zwar theoretisch wie das funktioniert, aber nicht was genau ich dafür jetzt machen muss.
Das Problem, was du zunächst mal lösen solltest, ist das Auffinden einer geeigneten Bibliothek für deine Mensch-ChatProgramm-Schnittstelle. Im Idealfall versteht diese Unicode auf irgend eine Art und Weise.
kein japaner schrieb:
Gibt es irgendwo ein Tutorial zu wstringstream, wstring, wchar_t, char16_t, ...? Muss ich da im Compiler noch etwas umstellen? Wie behandle ich Strings? Muss ich Ein/Ausgaben erst umwandeln? Alles irgendwie etwas verwirrend. Der Artikel hier im Forum über Unicode behandelt ja auch eher die Theorie. Zudem scheint er recht alt zu sein. Hat sich da mit C++11 was geändert?
wchar_t gehört noch zu den plattformspezifischen Zeichentypen. Was ein wchar_t genau ist, hängt also davon ab, wo Du dein Programm kompilierst. Das mit den Streams ist glaub'ich auch nicht geeignet für ein Chat-Programm, da Du ja sicherlich den Nutzer noch etwas eingeben lassen willst, während neu angekommene Nachrichten schon dargestellt werden. Also, ein getline(inputstream,stringvariable) für das blockierende Einlesen einer Zeile ist da schonmal unpraktisch. Gut, du könntest das mit mehreren Threads lösen, aber dann hat der Nutzer immer noch keine Möglichkeit, seine Eingabe vernünftig zu editieren.
Mit C++11 gibt es zwei neue Zeichentypen, die für Unicode (UTF-16 und UTF-32) gedacht sind, char16_t und char32_t. Und es gibt drei neue Zeichenkettenliterale (für UTF-8, UTF-16, UTF-32).
Plattformspezifische Kodierungen (seit C++98)
"alter hut" --> char[] (basic excecution character set) L"alter hut" --> wchar_t[] (extended character set)Dies muss jetzt nix mit Unicode oder ASCII zu tun haben. Aber unter Windows ist wchar_t, soweit ich weiß, 16-bittig und wird für UCS-2 (früher) und UTF-16 (heute) verwendet. Unter Linux ist wchar_t meines Wissens nach 32-bittig und wird für UTF-32 verwendet.
Unicode (seit C++11)
u8"neuer hut" --> char[] (UTF-8) u"neuer hut" --> char16_t[] (UTF-16) U"neuer hut" --> char32_t[] (UTF-32)Was einem hier schon auffällt ist, dass char[] zweimal auftaucht, also auch für UTF-8 Stringliterale verwendet wird. Ich kann also schreiben:
string x = "hello world"; string y = u8"hello world";was möglicherweise hier und da mal zu Fehlern führen könnte, wenn man da mit der Kodierung durcheinander kommt. für UTF-16/32 Zeichenketten gibt es dann noch u16string und u32string. Ich würde da für die interne Repräsentierung wahrscheinlich u16string verwenden, weil dann klar ist, dass das eine UTF-16 Kodierung ist und es nicht zu einer Verwechselung zwischen basic excecution character coding und UTF-8 kommen kann.
Inwiefern die C++11 Standardbibliothek Konvertierungen anbietet, weiß ich gar nicht. Damit habe ich mich bisher nicht wirklich auseinandergesetzt. Aber es gibt da eine nette Bibliothek namens UTF-CPP, die solche Konvertierungen durchführen kann und sogar Iterator-Wrapper anbietet, also mir aus zwei "Octet-Iteratoren" für eine "UTF-8 range" ein paar von Unicode-Codepoint-Iteratoren zaubert und solche Scherze ...
-
Korrektur:
Plattformspezifische Kodierungen (seit C++98)
"alter hut" --> char[] (excecution character set) L"alter hut" --> wchar_t[] (excecution wide-character set)Dies muss jetzt nix mit Unicode oder ASCII zu tun haben.
Man muss noch dazu sagen, dass "character set" im Sinne des C++ Standards nur eine Menge an Zeichen ist. Da wird noch gar nicht festgelegt, wie diese Zeichen alle durchnummeriert werden. Und das ist hier ja das Interessante. Und dazu kann man in §2.3/3 nachlesen:
[...] The values of the members of the execution character sets and the sets of additional members are locale-specific.
Ach, ist das alles schön kompliziert! ^^
Was ich auch komisch finde, ist, dass es kein u8-char-Literal gibt; denn 'A' ist ja nur dann 65, wenn das locale-specific encoding 'A' auch dem Wert 65 zuordnet. Gäbe es ein u8'A' wäre es immer 65 (nach Unicode). Man kann sich jedoch noch behelfen: static_cast<char>(u'A'), sofern man weiß, dass der Unicode Codepunkt unter 128 liegt.
Ich hoffe mal, dass die Jungs sich da alle etwas bei gedacht haben und dass mir der Kram nur ein bisschen komisch vorkommt, weil ich nicht den 100%gen Durchblick habe.

-
krümelkacker schrieb:
Was ich auch komisch finde, ist, dass es kein u8-char-Literal gibt; denn 'A' ist ja nur dann 65, wenn das locale-specific encoding 'A' auch dem Wert 65 zuordnet. Gäbe es ein u8'A' wäre es immer 65 (nach Unicode). Man kann sich jedoch noch behelfen: static_cast<char>(u'A'), sofern man weiß, dass der Unicode Codepunkt unter 128 liegt.
Laut Unicode definition sind alle ASCII Zeichen 1 zu 1 in Unicode mit der gleichen Codepunkt kodiert. -> ein ASCII Zeichen 'A'(65) hat auch in einem unicode codierung den wert 65. Dadurch können ASCII kodierte Zeichenketten problemlos auch als utf-8 kodierte Zeichenketten verarbeitet werden.
-
firefly schrieb:
Laut Unicode definition sind alle ASCII Zeichen 1 zu 1 in Unicode mit der gleichen Codepunkt kodiert. -> ein ASCII Zeichen 'A'(65) hat auch in einem unicode codierung den wert 65. Dadurch können ASCII kodierte Zeichenketten problemlos auch als utf-8 kodierte Zeichenketten verarbeitet werden.
Nur garantiert der C++ Standard nicht, dass ASCII zum Einsatz kommt und 'A' somit den Wert 65 hat. Zumindest ist mir nichts dergleichen bekannt und darauf wollte, glaub ich, auch Krümelkacker hinaus.
Grüssli
-
Dieser Thread ist imho sehr interessant für die FAQ.
MfG SideWinder
-
SideWinder schrieb:
Dieser Thread ist imho sehr interessant für die FAQ.
MfG SideWinder
Ja, merke ich schon einmal vor. Erstmal lasse ich ihn noch hier, wo er besser gesehen wird, falls noch jemand etwas hinzufügen möchte. Ich vermisse beispielsweise die C++11-Mittel, aber mehr als aus dem Handbuch/Standard abtippen kann ich da auch nicht, weil ich selber noch nicht damit gearbeitet habe. Oder über mögliche Schwierigkeiten bei den Codierungen (Z.B. UTF8: Zeichenzahl <-> Bytelänge). Oder über das Zusammenarbeiten mit den locales. Aber vielleicht ist jemand anders qualifizierter als ich, der ich der Einfachheit immer nur UTF-8 benutze, da man da nicht groß auf mögliche Probleme achten muss.
-
Wenn es in die FAQ geht, dann sollte man vielleicht noch zu Boost.Locale verlinken?
http://www.boost.org/libs/localeGrüssli
-
Dravere schrieb:
firefly schrieb:
Laut Unicode definition sind alle ASCII Zeichen 1 zu 1 in Unicode mit der gleichen Codepunkt kodiert. -> ein ASCII Zeichen 'A'(65) hat auch in einem unicode codierung den wert 65. Dadurch können ASCII kodierte Zeichenketten problemlos auch als utf-8 kodierte Zeichenketten verarbeitet werden.
Nur garantiert der C++ Standard nicht, dass ASCII zum Einsatz kommt und 'A' somit den Wert 65 hat. Zumindest ist mir nichts dergleichen bekannt und darauf wollte, glaub ich, auch Krümelkacker hinaus.
Grüssli
Um was für eine Kodierung soll es sich denn handeln, wo der lateinische Buchstabe 'A' nicht den dezimalwert 65 hat?.
Ich kenn nur ANSI/OEM codepages wo es sein kann, dass der dezimalwert 65 nicht für den lateinischen Buchstaben 'A' steht. Das sind dann meist codepages für sprachen, welche keine latainische Buschstaben verwenden (z.b. kyrilisch).
Und da stimmt das natürlich nicht mehr, dass man eine Zeichenkette (ein byte pro zeichen) auch als utf-8 kodiert ansehen kann.AFAIK: sobald Latainische Buchstaben enthalten sind, haben diese den entsprechenden Dezimalwert aus der ASCII Tabelle. Und dies gilt für alle unicode Kodierungen.
-
firefly schrieb:
Um was für eine Kodierung soll es sich denn handeln, wo der lateinische Buchstabe 'A' nicht den dezimalwert 65 hat?.
Mir bekannt ist zum Beispiel EBCDIC. Wird in IBM Mainframes verwendet.
Grüssli