[C++] Umgang mit Unicode

Simple Directmedia Layer: Portable Spieleprogrammierung
Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

[C++] Umgang mit Unicode

Beitrag von Glocke » So Okt 28, 2012 10:58 am

Hi,

von meiner SDL-Oberfläche lese ich einen String ein, der Unicode-Zeichen enthält. Diesen will ich per SDL_Net (also via Socket) an die Gegenseite schicken. Da ich mit dem Versenden von Strings bisher Probleme hatte, sende ich zuerst die Länge der Zeichenkette (als unsigned int) und dann jeden char (mit myString[index]) einzeln und lese auf der Gegenseite die entsprechenden Daten und rekonstruiere den String. Allerdings gehen dabei Sonderzeichen wie ß usw. verloren.

Wie gehe ich am besten mit Unicode-Characters um? Im Grunde könnte ich ja den int-Wert des Zeichens schicken und daraus das Zeichen rekonstruieren. Nur weiß ich nicht, wie ich an den Wert komme und wie ich quasi "zurück-caste". Mit normalen char ist das ja kein Problem ^^

Btw verwende ich kein .NET

LG Glocke

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: [C++] Umgang mit Unicode

Beitrag von cloidnerux » So Okt 28, 2012 11:09 am

Wie gehe ich am besten mit Unicode-Characters um? Im Grunde könnte ich ja den int-Wert des Zeichens schicken und daraus das Zeichen rekonstruieren. Nur weiß ich nicht, wie ich an den Wert komme und wie ich quasi "zurück-caste". Mit normalen char ist das ja kein Problem ^^
Auch ein Unicode-Zeichen ist nur eine Zahl, die etwas repräsentieren soll. Ein char ist auch eine Zahl, aber eben eine kleinere und ein "char" kann nach ASCII nicht so viele Zeichen einnehmen. Was du also machen musst, ist denn UNICDE-String Zahl für Zahl zu senden und zu wieder zu einem string zusammen bauen.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: [C++] Umgang mit Unicode

Beitrag von Glocke » So Okt 28, 2012 11:16 am

Soweit so gut, aber wie wandel ich meine Zahl (die ein Unicodezeichen repräsentiert) wieder zum Zeichen zurück? Ein cast zu char hilft da ja nicht.

LG Glocke

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: [C++] Umgang mit Unicode

Beitrag von fat-lobyte » So Okt 28, 2012 11:23 am

Glocke hat geschrieben:von meiner SDL-Oberfläche lese ich einen String ein, der Unicode-Zeichen enthält. Diesen will ich per SDL_Net (also via Socket) an die Gegenseite schicken. Da ich mit dem Versenden von Strings bisher Probleme hatte, sende ich zuerst die Länge der Zeichenkette (als unsigned int) und dann jeden char (mit myString[index]) einzeln und lese auf der Gegenseite die entsprechenden Daten und rekonstruiere den String. Allerdings gehen dabei Sonderzeichen wie ß usw. verloren.
Bist du sicher, dass das ein Unicode-Problem ist? Wenn deine Oberfläche tatsächlich unicode einliest und die Gegenseite tatsächlich Unicode empfängt, sollte es keine Probleme geben. Ich glaube, es liegt eher daran dass eine der Seiten eine andere Kodierung verwendet. Überprüf mal die einlesefunktionen der SDL bzw. dem was du auf der Gegenseite zum Anzeigen verwendest.
cloidnerux hat geschrieben:Auch ein Unicode-Zeichen ist nur eine Zahl, die etwas repräsentieren soll.
So ganz einfach ist das nicht. Das stimmt für UTF-32-Kodierte Zeichen, wenn sie aber UTF-8/UTF-16 kodiert sind, könnte es passieren dass sie in mehrere bytes aufgespalten werden, so wird schnell aus einem Zeichen 3 (nicht 2! Das unicode steuerzeichen kommt noch dazu.) bzw 5 Bytes.
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: [C++] Umgang mit Unicode

Beitrag von Xin » So Okt 28, 2012 11:27 am

Glocke hat geschrieben:Soweit so gut, aber wie wandel ich meine Zahl (die ein Unicodezeichen repräsentiert) wieder zum Zeichen zurück? Ein cast zu char hilft da ja nicht.
Das ist auch nicht nötig, denn eine ASCII-Zeichen ist eine Zahl und ein Unicodezeichen sind eine Reihe von Zahlen.

Bitte gib den String mal Zahl für Zahl aus, zum Beispiel so:

Code: Alles auswählen

char const * text = "Hello World";

unsigned int i=0;
while( text[i] )
{
  printf( "%d. Zeichen: %d\n", i, text[i] );
  i++;
};
Das machst Du auch auf der Empfängerseite.
Kommen die Zahlen identisch an?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: [C++] Umgang mit Unicode

Beitrag von nufan » So Okt 28, 2012 11:29 am

Glocke hat geschrieben:Soweit so gut, aber wie wandel ich meine Zahl (die ein Unicodezeichen repräsentiert) wieder zum Zeichen zurück? Ein cast zu char hilft da ja nicht.
Unicode Zeichen sind in SDL keine chars, sondern Uint16.

Einlesen kannst du das grob gesagt so:

Code: Alles auswählen

void readUnicode()
{ 
  SDL_EnableUNICODE( 1 );  
  SDL_EnableKeyRepeat( 400, 30 );

  // ...

  while( !done )
  {
    SDL_WaitEvent( &event );    
    switch( event.type )
    {
      case SDL_KEYDOWN:
                        unkey = event.key.keysym.unicode;
                        mod = event.key.keysym.mod;
                        // Gültige Taste und Strg ist nicht gedrückt.
                        if( unkey != SDLK_UNKNOWN && !(mod & KMOD_CTRL) )
                        {
                   
                          if( unkey == SDLK_BACKSPACE )
                          {
                            // Letztes Zeichen löschen.
                            // ...
                          }           
                          // Enter gedrückt -> Eingabe abbrechen, wenn Zeichen vorhanden sind.
                          else if( (unkey == SDLK_RETURN || unkey == SDLK_KP_ENTER) )
                          {
                            if (i > 0)
                              done = 1;    
                          }
                          // Gültiges Zeichen und es wurden weniger als 15 Zeichen eingegeben.
                          else if( i < 15 && unkey != SDLK_TAB && unkey != SDLK_ESCAPE )
                          {
                            // Zeichen an den Unicode-String (Uint16[]) dranhängen und Ausgabe aktualisieren.
                            // ...
                          }
                        }
                        break;
    }
  }
  
  SDL_EnableKeyRepeat( 0, 30 );
  SDL_EnableUNICODE( 0 );
}
Und darstellen damit:
http://www.libsdl.org/projects/SDL_ttf/ ... html#SEC45

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: [C++] Umgang mit Unicode

Beitrag von Glocke » So Okt 28, 2012 11:35 am

@Xin: Also auf beiden Seiten stimmt die Reihenfolge :)

@fat-lobyte: Das was von der Oberfläche eingelesen wird ist Unicode. Gebe ich den string außerdem mit std::cout aus, erscheinen die korrekten Symbole im Terminal. Auf beiden Seite des Sockets verwende ich SDL_Net - somit sollte die Kodierung die gleiche sein.

@nufan: Das Problem ist das Senden via Socket! Einlesen von der Oberfläche funktioniert.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: [C++] Umgang mit Unicode

Beitrag von Xin » So Okt 28, 2012 11:47 am

Glocke hat geschrieben:@Xin: Also auf beiden Seiten stimmt die Reihenfolge :)
Okay, Du empfängst also, was Du sendest.
Heißt, Du kannst das ganze Network-Zeugs als Fehlerquelle ausklammern, Du kannst Dir also überlegen, warum zwei Programme diese Zeichenreihenfolge mal so und mal so interpretieren.

Hast Du beide auf Unicode eingestellt?

Code: Alles auswählen

 SDL_EnableUNICODE( 1 );  
sehe ich bei nufan's Code, fehlt das beim Empfänger?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: [C++] Umgang mit Unicode

Beitrag von fat-lobyte » So Okt 28, 2012 11:55 am

Glocke hat geschrieben:@fat-lobyte: Das was von der Oberfläche eingelesen wird ist Unicode. Gebe ich den string außerdem mit std::cout aus, erscheinen die korrekten Symbole im Terminal. Auf beiden Seite des Sockets verwende ich SDL_Net - somit sollte die Kodierung die gleiche sein.
nufan hat geschrieben, dass die eingelesenen Zeichen Uint16 sind, das bedeutet sie sind UTF-16 kodiert.
Wenn du Zeichen mit std::cout ausgibst, wird erwartet, dass die Zeichen UTF-8 kodiert sind. Genau das wird wahrscheinlich das Problem sein.

Du könntest, wenn du auf Windows bist std::wcout verwenden, das verwendet statt char's wchar_t's. wchar_t ist auf Windows 16 Bit groß, auf Linux 32 Bit.

Ansonsten musst du deine Strings irgendwie umkodieren. Dazu kannst du entweder die libicu verwenden, oder wenn du C++11 verwenden kannst, irgendwie mit der String-Konvertierungslibrary: http://en.cppreference.com/w/cpp/string/multibyte
Haters gonna hate, potatoes gonna potate.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: [C++] Umgang mit Unicode

Beitrag von Glocke » So Okt 28, 2012 11:56 am

Wie eingangs gesagt, weiß ich nicht wie ich die einzelnen Unicode-Chars korrekt sende. Wandle ich jeden char des Strings in einen unsigned int um (um den Zahlenwert zu erhalten), bekomme ich ihn auf der Gegenseite nicht wieder zusammengesetzt, weil ich nicht weiß wie. Wie gesagt: Der cast zum char wäre ja Quatsch.

Und nein, auf beiden Seiten ist SDL-seitig Unicode aktiviert. Btw habe ich zu Testzwecken eine Variable mal direkt mit "asßdf" initialisiert. Dabei gibt es beim ß Probleme. Ich hole zeichenweise mit myString[index] die chars, caste die zum unsigned int und schicke die rüber. Für die Zeichenkette sendet er die Zahlen 97 ("a"), 115 ("s"), 4294967235, 4294967199, 100 ("d") und 102 ("f").

/EDIT: ich schau mir mal http://en.cppreference.com/w/cpp/string/multibyte an

Antworten