Probleme mit Umlauten



  • @HarteWare sagte in Probleme mit Umlauten:

    Das Thema Encoding, Unicode, UTF usw. ist schon etwas verwirrend manchmal... ich verstehe das bis heute nicht 100%, weil es mir einfach zu blöd ist 😃

    Das Problem fängt mit der Kodierung der Quelltextdatei an. Neuere Editoren nutzen da konsequent UTF-8, d.h. eine der möglichen Unicode-Kodierungen, ältere Editoren nutzen da irgend welche 8Bit oder sogar nur 7Bit Kodierungen. Dazu kommt das Thema Zeilenende je nach Plattform durch LF, CR, CR LF, LF CR, NL, … markiert wird. Wenn man also einen Quelltext schreibt, wird dieser von Editor kodiert und abgespeichert. Der Compiler muss in der Lage sein, den Code zu verarbeiten. Wahrscheinlich wird also ein EBCDIC Sourcecode auf einer ASCII Plattform und umgekehrt gar nicht compilieren, weil das z.B. kleine 'a'=0x81 in EBCDIC (das ist auch heute noch wegen der IBM Hosts wichtig) ist und in ASCII 'a'=0x61 ist. D.h. noch nicht einmal der Programmcode ist hier gleich kodiert, über irgend welche Sonderzeichen braucht man sich da erst recht keine Gedanken zu machen. D.h. man muss hier den Quelltext zuerst umkodieren, so dass er auf der jeweiligen Plattform auch verarbeitet werden kann.

    Wenn man nun eine der ASCII Spielarten hat, dann stimmt zumindest meistens (wenn da nicht NRCS genutzt wurde) der Quellcode in der Kodierung überein, d.h. das Programm lässt sich vom Compiler übersetzen und in ein lauffähiges Programm umwandeln. Aber je nachdem welche Kodierung Editor und Compiler nutzen kann es hier schon zu Problemen kommen. Mit NRCS werden unter anderem '[', ']' aus dem ASCII 7-Bit durch 'Ä und 'Ö' ersetzt, u.a. deshalb gab es die Trigraphs in C und C++.

    Am Ende kommt noch die jeweilige Locale Einstellung für das laufende Programm dazu, d.h. je nachdem was da eingestellt ist interpretiert die Konsole die Ein- und Ausgaben des Programms anders.

    Wenn man unbedingt verschiedene Kodierungen in einem Programm nutzen muss, empfiehlt es sich alle Zeichen explizit als Hexcode einzugeben und niemals dabei vergessen, dass das nur mit dem jeweiligen Encoding ein Sinn ergibt. Nimmt man Zeichen direkt z.B. 'a' kann das bereits zu Problemen führen, weil man Rekodieren der Sourcedatei das verändert würde. Will man aber auf einem Windows System ein EBCDIC 'a' verarbeiten können, muss dort der EBCDIC Code stehen und nicht der Windows Code für 'a'. Ansonsten empfiehlt es sich Unicode zu nutzen, da sind dann endlich die Probleme eliminiert, es verbleibt nur noch darauf zu achten wie die Unicode-Zeichen kodiert wurden UTF-8, UTF-16/UCS-2, UCS-4/UTF-32 bzw. UTF-EBCDIC.



  • Würde es hier nicht mehr Sinn machen, erst die Default-Locale zu laden und dann über diese Codepage zu fahren?



  • @eigenartig sagte in Probleme mit Umlauten:

    Würde es hier nicht mehr Sinn machen, erst die Default-Locale zu laden und dann über diese Codepage zu fahren?

    Nur dann wenn der Sourcecode des Programm die gleiche Codepage nutzt.



  • @john-0 sagte in Probleme mit Umlauten:

    Nur dann wenn der Sourcecode des Programm die gleiche Codepage nutzt.

    Das ist dann aber schonmal ein guter Ansatz das so zu machen.



  • Edit: Ach, vergesst meinen Beitrag, ich merke gerade dass der nur einen Teil der Problematik (Ausgabe) behandelte. UTF-16 mit wstring ist hier vielleicht für einen Anfänger am einfachsten zum Üben zu handhaben, wegen dem Index-Zugriff für einen grossen Teil des Coderaums - für vollständig korrekten Produktiv-Code sollte man sich jedoch von Index-Zugriffen auch bei UTF-16 verabschieden 😉

    UTF-8-Ausgabe unter Windows kann man übrigens zuverlässig hinbekommen, indem man die UTF-8-Konsolen-Codepage explizit mit einer WinAPI-Funktion setzt, auch ohne setlocale, wstring, u8-Präfix und dergleichen. Bei UTF-8-Kodierung kann man aber nicht mehr mit s[i] nach Umlauten suchen, sondern muss jedes Sonderzeichen wie einen Substring behandeln (von Kanonischer Normalisierung um verschiedene UTF-8-Codierungen des exakt selben Zeichens finden zu können will ich erst gar nicht anfangen):

    #include <iostream>
    #ifdef _WIN32
         #include <Windows.h>
    #endif
    
    auto main() -> int
    {
        #ifdef _WIN32
            SetConsoleOutputCP(CP_UTF8);
        #endif
        std::cout << "äöüß" << std::endl;
    }
    

    Läuft bei mir unverändert und wie erwartet mit GCC/Clang/MSVC kompiliert unter Windows Eingabeaufforderung, Powershell, MinTTY, WSL-Konsole mit Debian und unter Linux-VM mit Debian.

    Wichtig: Datei als UTF-8 speichern. Unter Visual Studio nennt sich das "Unicode (UTF-8 without signature) - Codepage 65001".



  • @Finnegan Wird das dann auch korrekt auf Systemen angezeigt wo die ausgegebenen Zeichen nicht in der 8-Bit System Codepage darstellbar sind? Also angenommen ich hab Windows auf Codepage 1253 (griechisch, enthält keine deutschen Umlaute) eingestellt, kann ich damit dann ein "ü" ausgeben so dass es korrekt in der Konsole angezeigt wird?



  • @hustbaer sagte in Probleme mit Umlauten:

    @Finnegan Wird das dann auch korrekt auf Systemen angezeigt wo die ausgegebenen Zeichen nicht in der 8-Bit System Codepage darstellbar sind? Also angenommen ich hab Windows auf Codepage 1253 (griechisch, enthält keine deutschen Umlaute) eingestellt, kann ich damit dann ein "ü" ausgeben so dass es korrekt in der Konsole angezeigt wird?

    AFAIK sollte es gehen, da durch SetConsoleOutputCP die console auf UTF-8 umgestellt wird. Die console muss nur ein Font verwenden welche auch die deutschen umlautet enthält.



  • @hustbaer sagte in Probleme mit Umlauten:

    @Finnegan Wird das dann auch korrekt auf Systemen angezeigt wo die ausgegebenen Zeichen nicht in der 8-Bit System Codepage darstellbar sind?

    Umgekehrt zu deinem Griechisch-Beispiel funktionierts: Griechisch und Kyrillisch wird damit ebenfalls problemlos angezeigt. Das sieht mir nicht wie eine "8-Bit-Codepage" aus. Devanagari allerdings nicht mehr. Ich vermute, das ist lediglich durch die Konsolen-Schriftart limitiert. Unter MinTTY hab ich eine sehr umfangreiche Schriftart, dort machen auch japanische Zeichen und Dinge wie "☠✂✐" keine Probleme. Leider kann ich die zum testen nicht in der Standard Windows-Konsole auswählen (die ist sehr pingelig bei den Font-Eigenschaften, da erscheint nicht jede Schrift in der Auswahlliste).

    Die Konsole wird auch mit SetConsoleOutputCP explizit auf UTF-8 umgestellt. Dein "Windows auf Codepage 1253" it läuft dann zumindest in dem einen Konsolenprozess auf UTF-8.



  • @Finnegan sagte in Probleme mit Umlauten:

    Umgekehrt zu deinem Griechisch-Beispiel funktionierts: Griechisch und Kyrillisch wird damit ebenfalls problemlos angezeigt.

    Danke 🙂

    Die Konsole wird auch mit SetConsoleOutputCP explizit auf UTF-8 umgestellt. Dein "Windows auf Codepage 1253" it läuft dann zumindest in dem einen Konsolenprozess auf UTF-8.

    Ich behaupte mal dass das nicht so ist. In der Doku zu SetConsoleOutputCP steht nichts zum Thema System Code Page/CP_ACP. Hätte ich auch noch nie gehört dass sich da was ändert. Zur Info: Die System Code Page ist jene Code Page die bei der UTF-16 <-> ANSI Konvertierung verwendet wird wenn man die "A" Funktionen verwendet (CreateFileA, SetWindowTextA etc.).



  • @hustbaer sagte in Probleme mit Umlauten:

    Ich behaupte mal dass das nicht so ist. In der Doku zu SetConsoleOutputCP steht nichts zum Thema System Code Page/CP_ACP. Hätte ich auch noch nie gehört dass sich da was ändert. Zur Info: Die System Code Page ist jene Code Page die bei der UTF-16 <-> ANSI Konvertierung verwendet wird wenn man die "A" Funktionen verwendet (CreateFileA, SetWindowTextA etc.).

    Ja, das habe ich schlamping formuliert. Der Name legt ja schon nahe, dass es sich nur auf die Konsolen-Ausgabe bezieht. Dass auch File- und andere Konvertierungen betroffen wären, hätte ich auch nicht erwartet.

    Ist dennoch ein netter Ansatz für plattfomübergreifende Software, bei der man sich für UTF-8 entschieden hat. Braucht natürlich UTF-8->UTF--16-Konvertierung für Dinge wie SetWindowText. Mit cout hat man dafür dann wenig Ärger.


Anmelden zum Antworten