u16string ausgeben?



  • Hallo Leute,

    Ich muss gezwungenermassen mit u16strings arbeiten, die ich ueber die Netzwerkschnittstelle hereinbekomme. Wie kann ich solche Strings korrekt ausgeben? Weder gibt es einen passenden operator << dafuer, noch gibt es ein u16cout.

    Gruesse,
    Der Kellerautomat



  • DU minst wahrscheinlich UTF-16, oder?

    schonmal ICU probiert?



  • Ja, ich habe std::u16strings, die UTF-16 kodiert sind. Sie kommen von einer Java Anwendung.

    Eine externe Bibliothek ausser Boost moechte ich ungerne verwenden.



  • Hast du schon versucht, durch den Iteratoren-Paar Konstruktor von wstring eine Temporary zu instantiieren und diese auszugeben?

    std::wcout << std::wstring(str.begin(), str.end());
    

    Soweit ich mir das durchdenke dürfte das doch gehen...





  • Sone schrieb:

    Hast du schon versucht, durch den Iteratoren-Paar Konstruktor von wstring eine Temporary zu instantiieren und diese auszugeben?

    std::wcout << std::wstring(str.begin(), str.end());
    

    Soweit ich mir das durchdenke dürfte das doch gehen...

    wstring muss nicht utf-16 kodiert sein. Unter Windows ist es das meines Wissen nach auch nicht. Und unter Linux ist es utf-8.



  • otze schrieb:

    Sone schrieb:

    Hast du schon versucht, durch den Iteratoren-Paar Konstruktor von wstring eine Temporary zu instantiieren und diese auszugeben?

    std::wcout << std::wstring(str.begin(), str.end());
    

    Soweit ich mir das durchdenke dürfte das doch gehen...

    wstring muss nicht utf-16 kodiert sein. Unter Windows ist es das meines Wissen nach auch nicht. Und unter Linux ist es utf-8.

    Unter Windows ist unicode (wchar_t = 16Bit) AFAIK eine UCS2 Kodierung und nicht UTF-16, da ein zeichen in ein wchar_t passt. Und mit der UTF-16 Kodierung können für ein zeichen auch 2 oder mehr 16bit blöcke benötigt werden.
    Unter linux ist wchar_t 32Bit groß und dann eher brauchbar für eine USC4 Kodierung.
    Aber das hat wenig damit zu tun das unter linux die utf-8 kodierung bevorzugt wurde. Diese kodierung hat nur den vorteil, dass bestehende programm auch texte in unicode "verarbeiten" können.

    PS: Angaben ohne Gewähr dass diese 100%ig richtig sind.


  • Administrator

    Unter Windows kommt nicht UCS-2 sondern UTF-16 zum Einsatz. Dass sich dieser Irrglaube immer noch hält, ist der Wahnsinn.
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd374081.aspx

    Für UTF-16 können zudem nur maximal zwei 16 Bit Blöcke verwendet werden.
    http://de.wikipedia.org/wiki/UTF-16

    @Kellerautomat,
    Muss es plattforumunabhängig sein oder kann man z.B. von Windows ausgehen? Eine plattforumabhängige Lösung ist mir nicht bekannt.

    Grüssli



  • Hallo Kellerautomat,

    falls Du bereits C++11 zur Verfügung hat, ist alles mit dem Standard zu machen, wenn Deine Plattform mitspielt (s.u.). Neben einem Konverter std::wstring_convert bietet C++11 auch die Facette std::codecvt_utf16 . Anbei eine kleine Demo, die die Anwendung zeigt:

    #include <iostream>
    #include <locale> // wstring_convert 
    #include <codecvt>  // codecvt_utf16
    #include <algorithm> // transform
    #include <iterator> // ostream_iterator
    
    int main()
    {
        using namespace std;
        cout << "sizeof(wchar_t)=" << sizeof(wchar_t) << endl;
    
        string euro = char(0x20) + string(1,char(0xAC)); // Das EURO-Zeichen in UTF-16
        string violinenschluessel = "\xD8\x34\xDD\x1E";
        string in = violinenschluessel + '\0' + string(1,'1') + '\0' + string(1,'0') +  euro; // '$10EUR' in UTF-16
    
        // --   input 'in' in UTF-16 nach s (Unicode) konvertieren
        std::wstring_convert< std::codecvt_utf16< wchar_t > > converter;
        wstring s = converter.from_bytes( in );
        cout << "Code fuer Violinenschluessel (0x1D11E) = 0x" << hex << int(s[0]) << dec << endl;
    
        // --  Ausgabe (mit Berücksichtigung nicht druckbarer Zeichen)
        const ctype< wchar_t >& ctype_ = use_facet< ctype< wchar_t > >( wcout.getloc() );
        transform( begin(s), end(s), ostream_iterator< wchar_t, wchar_t >( wcout << "Ausgabe-> " ), 
            [&ctype_]( wchar_t c )->wchar_t { return c < 0x7fff && ctype_.is( std::ctype_base::print, c )? c: wchar_t('?'); } );
        wcout << endl;
    
        return 0;
    }
    

    Bei der Ausgabe ist zu berücksichtigen, dass nicht jedes Device jedes Zeichen darstellen kann. Daher die Ausgabe mit ' transform ' und der Überprüfung mit std::ctype_base::print . Wobei ich nicht sicher bin, ob das mit isprint gemeint ist? Alles was nicht darstellbar ist, wird in der Demo durch '?' ersetzt.

    Unter VS10 ist das wchar_t nur 2Byte groß. Damit kann z.B. der Violinenschlüssel 0x1D11E gar nicht gespeichert werden, das Euro-Zeichen schon. Der Konverter macht aus dem Violinenschlüssel 0xD11E, der Konverter schneidet einfach vorne ab. 0xD11E wird dann später als druckbares Zeichen 'erkannt' - deshalb noch mal die Abfrage c < 0x7fff .

    Mit VS10 auf der Konsole ergibt sich folgender Output:

    sizeof(wchar_t)=2
    Code fuer Violinenschluessel (0x1D11E) = 0xd11e
    Ausgabe-> ?10?
    

    Btw.: die 'schöne' Lösung besteht meines Erachtens in einen basic_streambuf<wchar_t> , der gleich die Facette std::codecvt_utf16 auf den Input(Netzwerkschnittstelle) loslässt und schon ab dem lesenden Stream (gibt es den bei Dir überhaupt?) hat man es dann nur noch mit Unicode-Zeichen zu tun.

    Gruß
    Werner



  • Hallo,

    Danke fuer euere bisherigen Loesungen, das scheint ja alles nicht so einfach zu sein. Allerdings hat sich herausgestellt, dass bis auf 1-2 Zeichen nur Zeichen aus dem Extended ASCII Character Set gesendet werden. Daher muss es doch moeglich sein, diese Strings direkt durch abschneiden des jeweils zweiten Bytes in einen normalen std::string umzuwandeln, oder?

    Gruesse,
    Der Kellerautomat



  • Dravere schrieb:

    Unter Windows kommt nicht UCS-2 sondern UTF-16 zum Einsatz. Dass sich dieser Irrglaube immer noch hält, ist der Wahnsinn.
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd374081.aspx

    Ok sie verwenden "mittlerweile" UTF-16. Aber erst ab Windows 2000 wird UTF-16 voll unterstützt. Vorher war es UCS-2.


Anmelden zum Antworten