UTF-8 'durchschleifen'/konvertieren
-
Hallo, da bin ich wieder.... genauso dumm wie immer, wenn ich hier ankomme
Ich stehe mal wieder auf dem Schlauch und habe nicht genug Halbwissen, um ein Ganzes draus zu machen:
Ich habe ein C++-Programm, in dem ich analog des Socket-Tutorials aus diesem Forum (http://www.c-plusplus.net/forum/viewtopic-var-t-is-169861-and-start-is-0-and-postdays-is-0-and-postorder-is-asc-and-highlight-is-.html)
eine Serverabfrage starte. Diese liefert eine XML zurück. Encoding ist erwartungsgemäß UTF-8. Das Parsen der XML ist recht einfach, so dass ich auch keine 3rd-Party-Lib benötige (was ich gut finde).
Nur mit den Sonderzeichen habe ich mal wieder Probleme.Letztlich möchte ich folgendes:
1. Meine Download-Methode bekommt per Parameter eine Referenz von std::string.
2. An diese wird (quasi analog) Tutorial 'appended':dateiinhalt.append(buf, bytesRecv);
buf ist ein char[1024]!
3. speichern, kopieren, manipulieren etc. des std::string's in einer Klasse.
4. zwischendurch ggf. speichern und lesen in eine / aus einer Datei.
5. Darstellen per Wrapper. Dieser erwartet einen LPCTSTR.Internationale Sonderzeichen sollten bei 5. korrekt ankommen. Das File zwischendurch ist nicht für den Anwender gedacht.
Seid doch bitte so nett und teilt Eure Ideen mit einem Dummy
...
PS: Komischerweise hat der alte Programmstand inzwischen auch dazu entschieden, keine Umlaute mehr anzuzeigen. K.A., ob das evtl. an WinXP-SP3 liegt?!
-
Wenn der String in utf8 codiert ist kannst du ihn nicht einfach in einen LPCTSTR konvertieren (per cast). Bei utf8 haben die einzelnen Zeichen 1-4 Byte (variabel), wchar_t (nichts anderes verbirgt sich ja hinter LPCTSTR [zumindest wenn Unicode definiert ist]) hat aber eine feste Breite (im Falle von Windows wohl 2 Byte), char (wenn Unicode nicht definiert) 1 Byte.
Mit char funktioniert das ganze afaik, wenn eben keine Sonderzeichen auftreten (also nur ASCII, da passen die utf8 Werte in ein Byte).Lange Rede kurzer Sinn: moechtest du einen utf8-String an eine Funktion uebergeben, die wchar_t oder char erwartet (und letzteren nicht als utf8 interpretiert), wirst du um eine Konvertierung (und damit wahrscheinlich eine Bibliothek, da utf8 nicht so einfach zu handlen ist) herum kommen.
Wenn du utf8 nur "durchschleifen" willst, sollte das mit einem std::string funktionieren.
-
OK, also bedeutet das:
1. Das Speichern zwischendurch ist problemlos.
2. Das Manipulieren des Strings (trim, append, replace etc.) auch nicht.
3. Spätestens für die Ausgabe am Ende muss konvertiert werden.Wenn das stimmt, dann die Folgefragen:
4. Kann mir jmd. eine freie und kleine Source nennen, mit der die Konvertierung möglich ist? Ich werde ja kaum der erste sein, der mit C++ aus dem INet XML empfängt. Sollte aber ohne .NET etc. auskommen.
5. Wenn ich schon konvertieren muss, macht es dann Sinn, die Konvertierung gleich im ersten Schritt vorzunehmen?THX @DeSoVoDaMu (und ggf. weitere)
-
-
SammyRukka schrieb:
OK, also bedeutet das:
1. Das Speichern zwischendurch ist problemlos.
2. Das Manipulieren des Strings (trim, append, replace etc.) auch nicht.
3. Spätestens für die Ausgabe am Ende muss konvertiert werden.Nein, replace, lenght usw. funktioniert nicht, wenn in deinem std::string utf-8 ist. Nimm was besseres als std::string.
-
utfcpp ist mir auch schon über den Weg gelaufen. Da ich aber nur ein utf8To16 und umgekehrt gefunden habe, habe ich es irgendwie nicht ernst genommen.
Darf ich nach den letzen beiden Antworten jetzt trotzdem noch mal nachfragen?
Ich möchte utfcpp einsetzen (finde btw: aber die Lizenz gar nicht):
1. Kann ich konvertieren und normal meinen std:string benutzen?
2. Oder brauche ich einen wstring oder was auch immer (wenn ja, was?)?
3. Mit welchen utfcpp-API-Methoden bekomme ich das denn jetzt hin? Ich blicke noch nicht ganz durch, wie ich den Kram jetzt benutzen soll, gerade, wenn ich den String ggf. manipulieren und das ganze an einen LPCTSTR übergeben will.Sorry, gerade für 3., aber ich habe den Bogen wohl noch nicht raus (und hoffentlich nicht trotzdem schon überspannt).
THX to all!
-
SammyRukka schrieb:
1. Kann ich konvertieren und normal meinen std:string benutzen?
2. Oder brauche ich einen wstring oder was auch immer (wenn ja, was?)?Du musst dann auch einen Stringtyp verwenden der die konvertierten Daten aufnehmen kann, was wohl auf wstring hinausläuft. Es wird etwas schwierig UTF-8 das ja 1-4 Byte pro Zeichen hat, in einen auf char basierenden Typ verlustfrei zu konvertieren (Zumindest wenn dann jedes Zeichen gleichgroß sein soll).
cu André
-
asc schrieb:
Es wird etwas schwierig UTF-8 das ja 1-4 Byte pro Zeichen hat, in einen auf char basierenden Typ verlustfrei zu konvertieren (Zumindest wenn dann jedes Zeichen gleichgroß sein soll).
Du kannst mir Hoffnung machen. Was heißt das jetzt für mich? Lieber lassen und zum Golf fahren oder viel probieren und immer wieder hier nachfragen?
btw: Vielleicht sollte ich als XML-Parser einfach TinyXML einsetzen, vielleicht kann der mich korrekt beliefern
-
SammyRukka schrieb:
asc schrieb:
Es wird etwas schwierig UTF-8 das ja 1-4 Byte pro Zeichen hat, in einen auf char basierenden Typ verlustfrei zu konvertieren (Zumindest wenn dann jedes Zeichen gleichgroß sein soll).
Du kannst mir Hoffnung machen. Was heißt das jetzt für mich? Lieber lassen und zum Golf fahren oder viel probieren und immer wieder hier nachfragen?
Ich habe doch im Vorsatz auch gesagt, das es wohl intern wstring sein sollte.
Sprich Konvertierung von UTF-8 => std::wstring (Ich glaube unter Windows UTC-2, was auf jedenfall eine fixe Länge hat 1 Buchstabe ist 1 wchar_t). Für den Datenaustausch mag UTF-X ein gutes Format sein, zur internen Verarbeitung ist es sinnvoller mit einem Format zu arbeiten das eine Fixe Buchstabenlänge hat. Vor allem kannst du dann auch sinnvoll die Stringfunktionen darauf anwenden.Aber std::string scheidet aus da es auf char als internen Typ basiert. In der Regel reicht auch unter Windows der Typ wchar_t um Verlustfrei Infromationen zu halten (Wobei in der Regel heißt: Es gibt Alphabete auf der Welt die nicht in die ersten 65536 Zeichen passen, was aber für dich schätzungsweise unwichtig ist. Unter vielen Betriebssystemen != Windows ist wchar_t auch 4 Byte groß).
cu André
-
asc schrieb:
Ich habe doch im Vorsatz auch gesagt, das es wohl intern wstring sein sollte.
Sprich Konvertierung von UTF-8 => std::wstring (Ich glaube unter Windows UTC-2, was auf jedenfall eine fixe Länge hat 1 Buchstabe ist 1 wchar_t). Für den Datenaustausch mag UTF-X ein gutes Format sein, zur internen Verarbeitung ist es sinnvoller mit einem Format zu arbeiten das eine Fixe Buchstabenlänge hat. Vor allem kannst du dann auch sinnvoll die Stringfunktionen darauf anwenden.Aber std::string scheidet aus da es auf char als internen Typ basiert. In der Regel reicht auch unter Windows der Typ wchar_t um Verlustfrei Infromationen zu halten (Wobei in der Regel heißt: Es gibt Alphabete auf der Welt die nicht in die ersten 65536 Zeichen passen, was aber für dich schätzungsweise unwichtig ist. Unter vielen Betriebssystemen != Windows ist wchar_t auch 4 Byte groß).
Das stimmt so einfach nicht. wchar_t ist keinen Deut besser als char. Eigentlich sogar schlechter, weil char immerhin halbwegs verlässlich überall die gleiche Größe hat. Auf einem Unicodestring bringt einem die Längenangabe, die einem „primitive“ Bibliotheken liefern können nichts. Die liefern nämlich höchstens die Anzahl der Codepunkte, eine Information die annähernd so nutzlos ist wie die der Anzahl der Bytes eines UTF-8-kodierten Strings.
Alle anderen Stringfunktionen funktionieren wie gewohnt.Ich würde std::string nehmen und durchgängig UTF-8 benutzen. Konvertieren kannst du immernoch, wenn du was ausgeben willst (wenn das überhaupt notwendig werden sollte).
-
.filmor schrieb:
Das stimmt so einfach nicht. wchar_t ist keinen Deut besser als char.
Wenn du die Konvertierung die ich erwähne unterschlägst ja. Doch du kannst UTF-8 auch in eine Codierung umwandeln die auf einer festen Zeichenlänge arbeitet. Dann kann man auch die "„primitive“ Bibliotheken" verwenden.
cu André
-
Und was wäre das? Good-Old-Latin1?
-
.filmor schrieb:
Und was wäre das? Good-Old-Latin1?
Nein, wie wäre es aber z.B. mit UTC-2/UTC-4 oder wie sich das schimpft?
Sprich: Unicodesysteme die sich mit fester Breite im std::wstring unterbringen lassen.cu André
-
Hast du meinen Post denn nicht gelesen?
Es bringt dir absolut nichts, Unicode mit fester „Zeichenlänge“ zu speichern, da ein Unicode-Codepunkt eben nicht zwingend ein Zeichen geschweige denn ein Glyph ist. Der einzige „Vorteil“ ist, dass du dir keine ungültigen Zeichen durch unvorsichtiges abschneiden oder einfügen basteln kannst, aber das kann mit gewissenhafter Programmierung auch gut verhindert werden.
find etc. funktionieren natürlich auch mit UTF-8-Strings.
-
.filmor schrieb:
Der einzige „Vorteil“ ist, dass du dir keine ungültigen Zeichen durch unvorsichtiges abschneiden oder einfügen basteln kannst, aber das kann mit gewissenhafter Programmierung auch gut verhindert werden.
find etc. funktionieren natürlich auch mit UTF-8-Strings.Dann zeigt mal wie du ein funktionierendes lenght, find oder replace auf nem utf-8 string in nem std::string machst.
-
Length geht per Definition nicht anständig und ist auch wenig sinnvoll. find und replace tun's, wenn ich nach UTF-8 suche und mit UTF-8 ersetze. Wo ist das Problem?
-
.filmor schrieb:
Hast du meinen Post denn nicht gelesen?
Es bringt dir absolut nichts, Unicode mit fester „Zeichenlänge“ zu speichern, da ein Unicode-Codepunkt eben nicht zwingend ein Zeichen geschweige denn ein Glyph ist. Der einzige „Vorteil“ ist, dass du dir keine ungültigen Zeichen durch unvorsichtiges abschneiden oder einfügen basteln kannst, aber das kann mit gewissenhafter Programmierung auch gut verhindert werden.
find etc. funktionieren natürlich auch mit UTF-8-Strings.Ich habe jetzt nochmal nachgeschaut. Unter Windows wird intern wohl UCS-2 als 16 Bit Unicode verwendet. Ich Zitiere mal aus der wikipedia, und hebe die Stelle hervor:
UCS-2 (2-byte Universal Character Set) is an obsolete character encoding which is a predecessor to UTF-16. The UCS-2 encoding form is nearly identical to that of UTF-16, except that it does not support surrogate pairs and therefore can only encode characters in the BMP range U+0000 through U+FFFF. As a consequence it is a fixed-length encoding that always encodes characters into a single 16-bit value. As with UTF-16, there are three related encoding schemes (UCS-2, UCS-2BE, UCS-2LE) that map characters to a specific byte sequence.
Jetzt sag mir bitte was ich falsch verstehe. Ich weiß selbst das UTF-X nicht zwangsweise 1 Buchstabe für eine Basiseinheit X hat, aber zumindestens unter bestimmten Betriebssystemen wird für die Verwendung in der UI etc. auf ein System mit einer fixen Breite umgewandelt. Und wenn ich weiterhin Windows als beispiel verwende, dient hier dieses System auch als Basis für die Strings unter .Net.
Mag sein das ich manches falsch verstanden habe, aber sollte ich mich hier irren, so wäre das falschen Informationen über eben diese Formate zuzuschreiben (ich bin beileibe kein Unicodeexperte, habe mich damit aber auch schon länger Beschäftigt und recherchiert).
Und wenn man in einen System arbeitet wo eine Fixe Länge definiert ist, so sag mir warum die Algorithmen nicht funktionieren sollten.
cu André
-
@asc es geht wohl eher darum, dass es nichts bringt, auf wchar_t kodierungen umzuschwenken(die normal 16Bit lang sind), um dann wieder daten zu verliereren(eben die surrogate pairs).
Mein Vorschlag:
std::basic_string<unsigned int,char_traits<unsigned int> > utf32string.
mit:
template <typename octet_iterator, typename u32bit_iterator> u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
aus der gelinkten utf8 lib. Das reicht zumindest, solange du nicht mit streams rumhantieren musst. ab dann wird es eh, egal welche kodierung, richtig ekelhaft. Wenn man bedenkt, dass es standardlibs ohne wchar_t implementierung gibt, wird einem ganz schwarz vor augen, mit einem für C++ völlig fremden Zeichensatz zu arbeiten.
-
Mir geht's vor allem um solche Späße. Die machen alle Vorteile bis auf die beinahe garantierte Validität von UTF-32 oder ähnlichem zunichte.
-
.filmor schrieb:
Length geht per Definition nicht anständig und ist auch wenig sinnvoll. find und replace tun's, wenn ich nach UTF-8 suche und mit UTF-8 ersetze. Wo ist das Problem?
Das ist ja ein extremer Aufwand, dann musst du jede Benutzereingabe, Konstante usw. zuerst nach UTF-8 Konvertieren. So gut wie keine Funktion gibt dir UTF-8 zurück, wenn du jetzt einmal zu konvertieren vergisst, dann hast du so nen dummen Fehler nach dem du ewig suchst.