Unicode/Ansi: Eure Vorgehensweisen



  • Roger Wilco schrieb:

    Artchi schrieb:

    Außerdem kann z.B. die Windows-Konsole von Haus aus eh nur ASCII ausgeben.

    Ich benutze Locale-Objekte und trotzdem kann ich mit std::cout z.B. das €-Zeichen ausgeben (aus Windows-Konsole, während es std::wcout nicht kann. Das Gleiche gilt wieder für das Schreiben in eine Textdatei mittels std::(w)fstream.

    Auf deutsch: Es geht nicht mit der Windows-Konsole... Sie kann nun mal "nur" ASCII - da ist nichts mit L'€' oder so - '€' hingegen geht aber (weil es nun mal ASCII ist)

    bb



  • unskilled schrieb:

    Auf deutsch: Es geht nicht mit der Windows-Konsole... Sie kann nun mal "nur" ASCII - da ist nichts mit L'€' oder so - '€' hingegen geht aber (weil es nun mal ASCII ist)
    bb

    Ok, musste es eben auch feststellen. Also eher ein "Windows_Problem". Bedeutet also, dass man also bei Windows-Konsolen-Programmen (weiß nicht wie es unter Linux aussieht) std::cout verwenden sollte.

    Ich hätte einfach nicht gedacht, dass ich mit der Entscheidung durchgängig Unicode/wchar-Varianten zu benutzen, solche Probleme bekommen würde.



  • unskilled schrieb:

    Sie kann nun mal "nur" ASCII

    So schlimm ist es auch wieder nicht 😉 Soweit ich weiß, ist die Konsole nur durch die eingestellte Codepage eingeschränkt (fällt mit Verwendung von z.B. UTF-8 weg) und durch die Schriftart (es muss ein Glyph für den Character existieren).



  • Roger Wilco schrieb:

    Ok, musste es eben auch feststellen. Also eher ein "Windows_Problem". Bedeutet also, dass man also bei Windows-Konsolen-Programmen (weiß nicht wie es unter Linux aussieht) std::cout verwenden sollte.

    Ich hätte einfach nicht gedacht, dass ich mit der Entscheidung durchgängig Unicode/wchar-Varianten zu benutzen, solche Probleme bekommen würde.

    Warum kannst du kein wcout benutzen??? Huff... hast du dir überhaupt meinen Link oben angeschaut???

    Natürlich kann die Windows-Konsole auch Euro-Zeichen ausgeben, wenn es sein muß auch Kyrillisch. Es muß nur die richtige Codepage und/oder Font in der Konsole eingestellt sein. Das ist kein Problem von wcout, diese Schwierigkeit bekommst du mit jeder Programmiersprache.

    Und Widecharacter zu benutzen ist kein Fehler. Wenn die Windows-Konsole kein UTF-8 versteht, mußt du halt ein Locale mittels imbue() übergeben, die die Windows-Konsole versteht.

    Standard-mäßig ist in der dt. Windows-Konsole die CP 1252 eingestellt: das EURO-Symbol hat dort den Dezimalcode 128. Eine Locale im Stream müsste also entsprechend die Konvertirung vornehmen, damit du dich nicht drum kümmern bräuchtest. Oder es wird die Codepage in der Konsole umgestellt.

    Und ohne wcout wäre die Situation keinen Deut besser. Das Codepage-Thema würde immer noch da sein.

    Die Linux-Konsolen benutzen meines Wissens die Codepage UTF-8. D.h. du bräuchtest auch dort eine Locale im Stream, die in UTF-8 wandelt.
    Für einen Anfänger alles vielleicht verwirrend, weil tatsächlich umständlich. Les dir einfach mal meinen Link durch, dann wirds vielleicht einfacher.





  • Gib mal in deiner Windows-Konsole chcp ein, damit du erfährst, welche CP eingestellt ist.

    Mit chcp 857 kannst du z.B. auf die türkische CP umschalten.

    Mehr: http://technet.microsoft.com/en-us/library/bb490874.aspx

    Im Fenstermenü von der Konsole unter Eigenschaften > Schriftart > Lucida COnsole kannst du nen vernünftigen Font einstellen.



  • @Roger Wilco! Damit dir einiges verständlicher wird, wie die Konsole bzw. Codepages arbeiten:

    #include <iostream>
    
    void printAll()
    {
    	for(int i=0; i<256; i++)
    		std::wcout << (wchar_t)i;
    	std::wcout << std::endl;
    }
    int main()
    {
    	system("chcp 850");
    	printAll();
    	system("chcp 1252"); // Mit EUR-Symbol
    	printAll();
    }
    

    Dann aber den richtigen Font einschalten!



  • Danke Artchi für Deine Hilfe, ich hab's jetzt! 😉

    Vor einiger Zeit bin ich bei der Suche nach Thema auf ein Artikel gestoßen, in dem es ein Workaround zur Widechar-Ausgabe auf die Windows-Konsole (via std::cout) gab. Dort wurde behauptet std::cout unterstütze 256 Zeichen und std::wcout nur 128.

    Der Code dort funktionierte und das mit std::wcout habe ich naiver-weise einfach geglaubt.

    Hier nochmal ein Code-Beispiel, falls hier jemand landet, der gerne Unicode-Strings (std::wstring) auf die Konsole ausgeben möchte:

    #include <windows.h> // Get/SetConsoleOutputCP()
    #include <locale>    // std::locale
    #include <string>    // std::(w)string
    #include <iostream>  // std::(w)cout
    
    int main(){
    
        unsigned int oldCodepage = GetConsoleOutputCP(); // aktuelle Konsolen-Codepage sichern
        if(!SetConsoleOutputCP(1252)){ // Codepage 1252 (Westeuropa-Zeichensatz)
          std::cout << "Failed to setup Console-Codepage!" << std::endl;
            return 1;
        }
    
        std::locale gerLocal("german"); // alternativ std::locale("") (lädt Benutzer-Einstellung)
        std::locale::global(gerLocal);
        // alternativ einzelnd setzen:
        // std::cout.imbue(gerLocal); 
        // std::wcout.imbue(gerLocal);
    
        std::cout << "std::cout: \x80" << std::endl;
        std::wcout << L"std::wcout: \x20AC" << std::endl;
    
        std::cout << "std::cout: €" << std::endl; // geht zumindest bei mir (VC6.0)
        std::wcout << L"std::wcout: €" << std::endl;
    
        SetConsoleOutputCP(oldCodepage); // ursprüngliche Codepage wieder einstellen
        return 0;
    }
    

    Konsolenausgabe:

    std::cout: €
    std::wcout: €
    std::cout: €
    std::wcout: €

    Wichtig ist nur, wie Artchi schon sagte, dass eine Unicode-Schriftart in der Konsole aktiv ist (z.B. Lucida Console):

    WINAPI schrieb:

    If the current font is a fixed-pitch Unicode font, SetConsoleOutputCP changes the mapping of the character values into the glyph set of the font, rather than loading a separate font each time it is called. This affects how extended characters (ASCII value greater than 127) are displayed in a console window. However, if the current font is a raster font, SetConsoleOutputCP does not affect how extended characters are displayed.

    Und hier noch ein empfehlenswerter Link zum Thema The Standard C++ Locale



  • Ja, das mit dem Locale und imbue() ist entscheidend (hatte ich ja mehrmals geschrieben). Leider ist es echt schwierig auf solche Infos im Web zu stossen. Die Locales und Std-Streams werden leider sehr stiefmütterlich behandelt, weil die meisten C++-User diese sehr selten benutzen.

    Das man da aber einfach "german" als Locale verwenden kann, war mir so nicht bewusst.

    Aber eine Sache ist sehr gefährlich:

    // O.K.:
        std::cout << "std::cout: \x80" << std::endl;
        std::wcout << L"std::wcout: \x20AC" << std::endl;
    
        // Gefährlich:
        std::cout << "std::cout: €" << std::endl; // geht zumindest bei mir (VC6.0)
        std::wcout << L"std::wcout: €" << std::endl;
    

    Wenn das EUR-Symbol direkt eingegeben wird, ist es Quelltext-Editor- und System-abhängig. Weil du dann das Symbol so eingibst, wie es dein Editor oder OS verstehen. Die \x-Variante ist vorzusziehen, da so eindeutig wird, welches Sonderzeichen gemeint ist.

    Danke für den Beispielcode! 👍



  • Artchi schrieb:

    Wenn das EUR-Symbol direkt eingegeben wird, ist es Quelltext-Editor- und System-abhängig. Weil du dann das Symbol so eingibst, wie es dein Editor oder OS verstehen. Die \x-Variante ist vorzusziehen, da so eindeutig wird, welches Sonderzeichen gemeint ist.

    Wann genau wird das gefährlich? Wie muss ich mir das vorstellen: OS+IDE nutzen z.B. irgendeine Codepage bei der das EUR-Zeichen den Hex-Code xyz hat und der wird dann in den String gespeichert? Ich dachte, dass wird vom Editor entsprechend umgesetzt. Immerhin unterscheidet er ja auch "€" und L"€", was unterschiedliche Hex-Codes ergibt.

    Welche Zeichen sollte man dann lieber per Hex-Code eingeben? Dann sind ja theoretisch alle Zeichen nur per Hex-Code eindeutig.



  • Wenn du dir die verschiedenen Codepages anschaust (inkl. Unicode), wirst du feststellen, das alle Zeichen bis 128 gleich sind. Und das sind konkret gesagt die ersten 128 Zeichen vom US-ASCII. Die kannst du also über das Keyboard direkt eingeben. Alles was dadrüber ist, ist in jeder Codepage potenziell anders. Das EURO-Zeichen als 129. Zeichen zählt dazu.

    Meine beiden Schleifen in dem oberen Beispiel machen das auch deutlich.


Anmelden zum Antworten