Linux Unicode SAP NW SDK / Parsing / Mysqlpp
-
Hallo,
ich habe leider gleich mehrere Fragen zum Thema Unicode auf welche ich per
Google nicht wirklich die passenden Antworten gefunden habe. Aber vielleicht
kann mir ja hier jemand weiter helfen und meine Verständnisprobleme lösen.Bisher habe ich nur mit non Unicode Programmiert und werde jetzt ins kalte
Wasser geworfen, da wir Unicode Systeme bekommen haben und meine Anwendungen
damit umgehen müssen.Auch Teilantworten können mir schon weiter Helfen also lieber ein Post mehr als zu wenig - DANKE -
Zum System (Umgebung)
OS: SuSE Linux Enterprise 11 Kernel: 2.6.32.12-0.7-default #1 SMP (x86_64) GCC: (g++ -v) gcc version 4.3.4 [gcc-4_3-branch revision 152973] (SUSE Linux) LOCALES: LANG=POSIX LC_CTYPE=en_US.UTF-8 LC_NUMERIC="POSIX" LC_TIME="POSIX" LC_COLLATE="POSIX" LC_MONETARY="POSIX" LC_MESSAGES="POSIX" LC_PAPER="POSIX" LC_NAME="POSIX" LC_ADDRESS="POSIX" LC_TELEPHONE="POSIX" LC_MEASUREMENT="POSIX" LC_IDENTIFICATION="POSIX" LC_ALL= SAP NW RFC: liefert UTF16 als unsigned short // müsste ja unsigned short int sein. (in C geschrieben) lässt sich aber mit g++ kompilieren und in cpp Dateien ansprechen)
Frage #1: welchen Datentyp setze ich jetzt für Unicode ein? und gibt es für Linux einen Standard?
Ich muss die Daten vom SAP NW SDK entgegen nehmen.
In meiner Anwendung auswerten (Text Parsen)
und Teile davon in die Mysql DB schreiben
(Felder sind als UTF8 angelegt)Gefunden habe ich bisher:
- wchar_t << Windows ??? (wprintf "%ls" / ...) - char16_t - unsigned short << SAP NW SDK - weitere ?
Ist std::string eigentlich Unicode fähig?
Also wenn ich dann mit den "normalen" Stringfunktionen
komme und Zeichen auslese und ausgebe.
(Ich denke dass Unicode Zeichen mit mehreren Bits
kodiert sind und darum wahrscheinlich nichts
brauchbares mehr heraus kommt)Frage #2: Gibt es für unsigned short auch Funktionen wie substr ...
Frage #3: Wie übergebe ich die Daten der mysql++ ?
Vielleicht erübrigt sich das wenn die anderen Fragen beantwortet sind.
Aber im Handbuch http://tangentsoft.net/mysql++/doc/html/userman/unicode.html
wird leider nur lapidar gesagt dass die Mysql++ Unicode für Linux kann.
Intern wird soweit ich das gesehen habe ein mysqlpp::string verwendet welcher
wohl meine Vermutung von std::string abgekupfert ist.Frage #4: Kann es sein dass der GDB Unicode schon interpretiert und
mir nicht die beiden Bits bei UTF16 anzeigtDanke schon im Voraus für eure Hilfe.
Im Moment weiß ich zwar so ungefähr wie Unicode aufgebaut ist, aber nicht wie man damit in C / C++ umgeht.Vielleicht habt ihr ja bei euch ein paar Code Snips liegen,
welche mir auch weiter helfen könnten.-DANKE-
-
Erst einmal musst du beachten, dass es für Unicode unterschiedliche Repräsentationen gibt. Unter Linux verwendet man in der Regel UTF-8. UTF-8 ist eine Repräsentation von Unicode die kompatibel mit 8-Bit Zeichenrepräsentationen ist (char). Man muss jedoch beachten, dass in UTF-8 ein Zeichen mehrere Bytes groß sein kann (Multibyte-Encoding). UTF-8 ist außerdem ASCII kompatibel.
und gibt es für Linux einen Standard?
Was meinst du mit Standard? Es gibt diverse Standards die in Linux implementiert sind: POSIX, SUS, LSB etc.
Die Beschreibung der Standard-Funktionen findest du in den Manpages. Ansonsten gibt es das Handbuch der glibc: http://www.gnu.org/s/libc/manual/
Für Dinge die näher am System sind, gibt es noch http://kernel.org/doc/
Ist std::string eigentlich Unicode fähig?
Nein. Die C++-Standardlibrary ist nicht wirklich Unicode fähig. Man kann ohne Probleme ein UTF-8 String in einem std::string speichern. Aber das heißt nicht, dass die Funktionen auch das richtige tun. std::string weiß nichts über Multibyte-Encodings. So gibt std::string::size() dann die Anzahl der Bytes und nicht die Anzahl der Codepoints oder Grapheme aus. operator[] greift byteweise zu und substr kann sogar kaputte UTF-8 Strings liefern, wenn man in einem codepoint trennt.
Solange du UTF-8 also nur speichern willst, ist std::string in Ordnung. Wenn du aber auf dem String arbeiten willst, dann brauchst du Hilfsfunktionen. utf8-cpp ist eine einfache Implementierung die einem hilft mit UTF-8 umzugehen.
Frage #2: Gibt es für unsigned short auch Funktionen wie substr ...
Du kannst dir ja einen eigenen String-Typen generieren:
typedef std::basic_string<unsigned short> u16string;
(ggf. musst du char_traits implementieren).ABER unsigned short ist auf den meisten Systemen 16 Bit breit und daher vermutlich UTF-16. Auch UTF-16 ist ein Multibyte-Encoding! Daher trifft hier das gleiche zu, wie bei std::string!
Frage #3: Wie übergebe ich die Daten der mysql++ ?
Das steht ja, dass sie UTF-8 erwarten.
Frage #4: Kann es sein dass der GDB Unicode schon interpretiert und
mir nicht die beiden Bits bei UTF16 anzeigtDu meinst die beiden Bytes? Ich weiß nicht, ob GDB intern spezielle Unterstützung für Unicode hat. Aber die Terminal-Emulationen unterstützen in der Regel UTF-8 und haben kein Problem damit UTF-8 Strings richtig auszugeben
----
Also, wenn du nur Daten von SAP in MySQL speichern willst, dann reicht es, wenn du die Repräsentationen konvertierst. Dafür gibt es einfacherweise iconv. Damit kannst du dann von UTF-16 (Ich nehme mal an, das SAP UTF-16 benutzt) in UTF-8 konvertieren und andersrum. Die libstdc++ (Implementierung der C++ Standardbibliothek unter Linux) bietet eine Implementierung von std::codecvt auf Basis von iconv an: http://gcc.gnu.org/onlinedocs/libstdc++/manual/facets.html
Wenn du die einzelnen Codepoints auslesen willst oder überprüfen willst, ob ein String gültiges UTF-8 ist, dann solltest du (wie erwähnt) UTF8-CPP dir anschauen.
Brauchst du eine volle Implementierung des Unicode-Standards (also auch Dinge wie Collation, Grapheme-Splitting, Normalisierung, etc.), dann wird wohl derzeit kein Weg an ICU vorbei führen. ICU ist eine ziemlich große und hässliche Bibliothek von IBM.
Siehe auch: http://www.cl.cam.ac.uk/~mgk25/unicode.html
-
Danke schon mal für Ihre Antworten.
Diese Antworten habe ich schon fast erwartet. Nun gibt es aber doch auch den wchar_t Datentyp, welcher wohl speziell für Wide Chars geeigent ist also doch genau das was man dann für Unicode UTF8 verwenden sollte. Das habe ich mit Standard gemeint also einen Datentypen für das Hantieren mit UTF8.
Dann müsste ich vom SAP unsigned short welcher UTF16 ist mit der iconv Funktion nach UTF8 umwandeln. Dann müsste ich doch diesen WCHAR_T Typ erhalten mit dem
ich dann fast wie mit einem Char Array arbeiten kann ohne mir darüber Gedanken zu machen mit wie vielen Bytes ein Char nun repräsentiert wird.Und wenn ich Sie richtig verstehe nehme ich dann denn wchar_t Datentyp und schiebe denn quasi binär in die Mysql++ ?
Die UTF8-cpp werde ich mir gleich mal zu Gemüte führen
-
[quote]Nun gibt es aber doch auch den wchar_t Datentyp, welcher wohl speziell für Wide Chars geeigent ist also doch genau das was man dann für Unicode UTF8 verwenden sollte. Das habe ich mit Standard gemeint also einen Datentypen für das Hantieren mit UTF8.[/quote
wchar_t ist nicht für UTF-8! wchar_t ist für ein anderes Unicode-Encoding. Unter Linux ist es für UTF-32 und unter Windows ist es für UTF-16. UTF-32 hat den Vorteil, dass es ein Fixedbyte-Encoding für Unicode ist. Ein Codepoint ist also immer genau 4 byte (32 bit) lang. Dafür sind die Speicheranforderungen enorm.
Dann müsste ich vom SAP unsigned short welcher UTF16 ist mit der iconv Funktion nach UTF8 umwandeln. Dann müsste ich doch diesen WCHAR_T Typ erhalten mit dem
ich dann fast wie mit einem Char Array arbeiten kann ohne mir darüber Gedanken zu machen mit wie vielen Bytes ein Char nun repräsentiert wird.Und wenn ich Sie richtig verstehe nehme ich dann denn wchar_t Datentyp und schiebe denn quasi binär in die Mysql++ ?
Nein, für UTF8 bekommst du char!
-
Tux12Fun schrieb:
Frage #3: Wie übergebe ich die Daten der mysql++ ?
Hier möchte ich eine Warnung anbringen: mysql unterstützt nur einen Teil von Unicode, die sogenannte BMP. Diese Einschränkung ist gravierend, denn der Name "utf8" bei mysql scheint zu bedeuten, dass Unicode unterstützt wird. Wird es nicht. Es wird nur ein Teil unterstützt: http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html
Alle gängigen Zeichen sind da aber enthalten, insofern wirst du normalerweise keine Probleme bekommen. Aber wenn dein Programm Unicode-Daten woanders her bekommt, kann es passieren, dass du die einfach nicht speichern kannst in einer mysql-Tabelle, zumindest solange die Tabelle eines der unicode-Encodings trägt. Ich schreibe gerade an einer LaTeX-Datei, in der häufiger ein Zeichen außerhalb der BMP auftaucht: 𝔅. So ungewöhnlich ist es also nicht, dass ein User so ein Zeichen eingeben und speichern möchte.
-
Aber ein normaler char kann die UTF8 Daten ja nicht aufnehmen (muss dass dann nicht ein unsigned char sein?) und wenn ich ein Char Array habe wird ein "Buchstabe/Zeichen" durch mehrere Chars gebildet.
Das hat dann zur Folge dass mir keine Funktion mehr zur Verfügung steht mit der ich z. B. so etwas machen könnte. Gibt es für so etas dann "String" Funktionen die das UTF8 Format im Char Array richtig interpretieren ?
char utf8_array[512]; // << Contains UTF8 Data for (int i=0; i < 512; i++){ if (utf8_array[i] == '<' ){ cout << "TAG open found!" << endl; break; } }
Ah ok jetzt weiß ich dass wchar_t UTF32 repräsentiert.
Mein Problem ist wohl dass ich noch zu Ansi lastig denke
-
Christoph schrieb:
mysql unterstützt nur einen Teil von Unicode, die sogenannte BMP. Diese Einschränkung ist gravierend, denn der Name "utf8" bei mysql scheint zu bedeuten, dass Unicode unterstützt wird. Wird es nicht. Es wird nur ein Teil unterstützt: http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html
Oh, ich sehe gerade dass meine Information veraltet ist. Man kann ab Mysql 5.5 wohl utf8mb4 nehmen statt utf8 und hat dann auch Unterstützung für die restlichen Zeichen. Betrachte meinen Einwand als gegenstandlos.
-
Danke für den Hinweis da die Daten max.
Anschriften von Kunden enthalten können
werde ich hoffentlich von solchen Zeichen verschont.*Hoffnung*
-
Das Beispiel ist in Ordnung. UTF-8 wurde extra ASCII kompatibel entworfen. Die ganzen Multibyte-Sachen haben alle das MSB gesetzt und es kommt daher nicht zu Verwechselung mit gültigen ASCII Zeichen.
Etwas umständlicher ist es natürlich bei nicht-ASCII Zeichen. Da nun - wie du gesagt hast - ein Zeichen mehrere Bytes benötigt. Da würde aber folgender Code funktionieren
char utf8_array[512]; // << Contains UTF8 Data char const utf8c[] = "ü"; for (int i=0; i < 512 - sizeof(utf8c) + 1; i++){ if (memcmp(utf8_array+i, utf8c, sizeof(utf8c) - 1) == 0){ cout << "ü found!" << endl; break; } }
Wenn du wirklich die einzelnen Codepoints auslesen willst, dann benutze am besten utf8-cpp oder konvertiere den String in UTF-32.