Probleme mit Umlauten



  • @john-0 Interessant, was soll ich jetzt machen, damit das funkioniert, mir ist nicht ganz klar...



  • @germanveryhard Da dein System (Betriebssystem/Compiler) ein großes Geheimnis ist, ist genaue Hilfe schwierig.

    Auf Windows hat die Konsole (dat schwarze Fenster) eine andere Zeichenkodierung als der Rest vom System.

    Man kann den Compiler die Übersetzung der Zeichen machen lassen. Irgendwo gibt es dafür Einstellungen.

    Die einfachste Lösung ist aber: Verzichte auf Umlaute für die Lernprogramme.



  • @DirkB Mein Betriebssystem ist Windows und mein Compiler ist gcc 8.2.0.



  • @germanveryhard
    Dann änder die ersten Zeilen mal so ab:

    #include <iostream>
    using namespace std;
    
    int main(){
    	const unsigned char AE = static_cast<unsigned char>(142);
    // ... Rest wie gehabt
    


  • @Belli Das hat nichts geaendert... Immer noch nur Fragezeichen...



  • 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 grundsätzlich bei

    if (s[0] == 'Ü')
    

    ist, dass Du davon ausgehst, dass 'Ü' als ein einziges Byte im String repräsentiert wird. Das muss aber nicht zwingend für jedes Zeichen der Fall sein, irgendwelche wilden Zeichen könnten z. B. in Wirklichkeit zwei Bytes im std::string belegen. Beispiel UTF-8 Kodierung, schau mal das Beispiel an:

    string s = u8"Übung";
    std::cout << "Length: " << s.size() << '\n';
    

    Man würde hier meinen, dass Länge von s == 5 ist, aber das ist es hier eben nicht, weil manche Zeichen (einzelne Unicode Code-points) mit mehr als nur einem Byte kodiert sein können. Bei ASCII ist zwar UTF-8 "backwards compatible", d.h., es ist garantiert, dass jedes ASCII Zeichen nur ein einziges Byte in UTF-8 benötigt. Bei Ü ist dies aber eben nicht garantiert. Deshalb ist es auch schwierig, nur anhand von s[0] ein Zeichen im String zu Vergleichen.

    Das würde also z. B. funktionieren:

    string s = u8"Übung";
    if (s.find(u8"Ü") == 0) {
    	cout << "LALA";
    }
    

    Oder

    	string s = "Übung";
    	if (s[0] == '\u00DC') {
    		cout << "LALA";
    	}
    

    Wobei ich hier keine Ahnung habe, welche Kodierung "Übung" hat und warum genau das funktioniert.
    Ich empfehle auf Englisch umzusteigen, und bei ASCII zu bleiben...

    Evtl. nützliche Links:



  • @germanveryhard
    gibst Du das denn auch in der Konsole aus? Also nicht in der IDE auf Run klicken, oder den Debugger ausführen, sondern eine Konsole öffnen, ins Programmverzeichnis wechseln, und dort dann die *.exe starten!

    Wie DirkB oben schon schrieb: die Konsole hat eine andere Zeichencodierung als der Rest vom Windows-System!



  • @HarteWare sagte in Probleme mit Umlauten:

    Das Problem grundsätzlich bei

    if (s[0] == 'Ü')
    

    Das hat er ja gar nicht gemacht, ich wette, DAS würde funktionieren! Er vergleicht aber s[0] nicht mit dem 'Ü', das seine IDE zur Verfügung stellt, sondern mit dem 'Ü', wie es die Konsole codiert.



  • @HarteWare Ok die erste Methode funkioniert, aber die erste nicht, aber egal, danke! Ich würde auf Englisch umsteigen, aber die Aufgabe, die ich lösen muss, ist einfach so, dass ich das brauche...



  • Dieser Beitrag wurde gelöscht!


  • @Belli Oh stimmt, jetzt funktioniert das bei mir auch... Habe ich wohl davor irgendwas falsch gemacht.
    Naja wie gesagt, ich habe das Thema selbst nicht 100% durchschaut, daher sind meine Aussagen alle mit äußerster Vorsicht zu genießen...



  • @germanveryhard sagte in Probleme mit Umlauten:

    ig

    Wie kommst du eigentlich auf die Zahlen 142, 132, 153,...?

    #include <iostream>
    
    using namespace std;
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("input.txt", "r", stdin);
    	freopen("output.txt", "w", stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    
    	const unsigned char AE = static_cast<unsigned char>(142);	// Wie kommst du auf diese Zahlen?
    	const unsigned char ae = static_cast<unsigned char>(132);
    	const unsigned char OE = static_cast<unsigned char>(153);
    	const unsigned char oe = static_cast<unsigned char>(148);
    	const unsigned char UE = static_cast<unsigned char>(154);
    	const unsigned char ue = static_cast<unsigned char>(129);
    	string s = "Übung";
    
    	if (s[0] == UE){
    		cout << "LALA";
    	}
    	cout << "Tüpfelhyäneöhrchenstraße\n";
    	printf("Coding of Ü: %i\n", static_cast<unsigned char>('Ü'));	
    	cout << "Coding of UE: " << static_cast<int>(UE) << "\n";
    	printf("Coding of s[0]: %i\n", s[0]);
    	printf("Coding of Ü (signed): %i\n", static_cast<char>('Ü'));
    
    	cout << AE << " " << OE << " " << UE << " " << ae << " " << oe << " " << ue;
    	return 0;
    }
    

    Wenn ich das Programm ausführe, so erhalte ich folgende Ausgabe:

    Tüpfelhyäneöhrchenstraße
    Coding of Ü: 220
    Coding of UE: 154
    Coding of s[0]: -36
    Coding of Ü (signed): -36
    Ž ™ š „ ” 
    

    Du codierst den Buchstaben Ü mit der Zahl 154, der Compiler möchte hier aber eine 220 sehen. DIes entspricht der Codierung mittels Codepage 1252. Dort ist das Zeichen hexdezimal mit 0xDC codiert. Wandele ich diese Zahl in dezimal um, so erhalte ich 220. Da bei mir char als signed interpretiert wird, läuft bei mir die Zahl 220 über, d.h. ich muss 256 = (2**8) abziehen: 220 - 256 = -36, uns siehe da, diese Zahl entspricht s[0].

    So sollte es funktionieren:

    #include <iostream>
    
    using namespace std;
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("input.txt", "r", stdin);
    	freopen("output.txt", "w", stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    
    	const char AE = 'Ä';
    	const char ae = 'ä';
    	const char OE = 'Ö';
    	const char oe = 'ö';
    	const char UE = 'Ü';
    	const char ue = 'ü';
    	string s = "Übung";
    
    	if (s[0] == UE){
    		cout << "LALA";
    	}
    	/*cout << "Tüpfelhyäneöhrchenstraße\n";
    	printf("Coding of Ü: %i\n", static_cast<unsigned char>('Ü'));	
    	cout << "Coding of UE: " << static_cast<int>(UE) << "\n";
    	printf("Coding of s[0]: %i\n", s[0]);
    	printf("Coding of Ü (signed): %i\n", static_cast<char>('Ü'));*/
    
    	cout << AE << " " << OE << " " << UE << " " << ae << " " << oe << " " << ue;
    	return 0;
    }
    


  • In CP850 ist Ä als 142 dezimal kodiert.
    Und afaik ist/war CP850 lange zeit die default codepage für die windows cmd.exe console



  • Sorry @Quiche-Lorraine, aber du hast Codepages nicht verstanden.
    Es geht bei dem Programm von @germanveryhard ja um die Konsolenausgabe, nicht darum, welches Encoding beim Kompilieren verwendet wird (was ja von dem Encoding der ".cpp"-Quelldatei abhängig ist, zumindestens wenn man kein spezielles Encoding, so wie in dem Beispiel von @HarteWare, angibt).

    @germanveryhard: Gib mal mit chcp die aktuelle Codepage auf deiner Konsole aus. Standardmäßig sollte es unter Windows 10 immer noch, wie @firefly schon geschrieben hat, 850 (also "„Multilingual (DOS-Latin-1)“, westeuropäische Sprachen") sein, s.a. Codepages - und dann sollte es so mit deinem Code funktionieren. Oder benutzt du eine IDE und startest daraus dann eine Konsole (dann kann es schon sein, daß diese ein anderes Encoding eingestellt hat)?

    Du kannst aber auch über C++ das Encoding einstellen mit std::locale. Standardmäßig ist "C" (englisch ASCII) eingestellt, aber mittels std::locale::global(std::locale("")); kannst du auf das Encoding deiner Betriebssystem-Umgebung umstellen (dies sollte dann hier in Westeuropa 1252 "Westeuropäische Sprachen" sein), so daß du dann auf die DOS-Umlaute verzichten kannst.

    Einen detaillierten Beitrag dazu gibt es auch unter facet ändern.



  • @Th69 sagte in Probleme mit Umlauten:

    Es geht bei dem Programm von @germanveryhard ja um die Konsolenausgabe, nicht darum, welches Encoding beim Kompilieren verwendet wird

    Jaein, es geht mir auch um die folgende Stelle.

            const unsigned char UE = static_cast<unsigned char>(154);
            const unsigned char ue = static_cast<unsigned char>(129);
            
            string s = "Übung"; 
            if (s[0] == UE){
            	cout << "LALA";
            }
    

    Eigentlich müsste in der Ausgabedatei output.txt ?????????? oder ähnliches stehen und nicht ??????. Tut es aber nicht, da der Vergleich schon fehlschlägt. Warum?



  • @Quiche-Lorraine sagte in Probleme mit Umlauten:

    ... ?????????? oder ähnliches stehen und nicht ??????

    Wolltest du hier auch Unicode-Zeichen posten? 🙂

    Natürlich schlägt der Vergleich schon fehl, da ja das 'Ü' in dem String in dem Encoding der CPP-Quelldatei steht (z.B. als UTF-8 abgespeichert) und eben nicht im Encoding der Konsole.



  • @Th69 sagte in Probleme mit Umlauten:

    Wolltest du hier auch Unicode-Zeichen posten?

    Ja gerne:

    Ž ™ š „ ” 

    🙂

    Aber zurück zum Thema: Ich verstehe die Sache mit dem Encoding der Konsole und dem Vergleich nicht. Was hat denn ein Vergleich der Form if (s[0] == UE) mit dem Encoding der Konsole zu tun?



  • Ja, eben nichts (darum macht es ja auch keinen Sinn die Zeichen auf diese Art zu vergleichen).

    Also entweder:

    // benutze Encoding der Quellcodedatei (d.h. vom Compiler eingestellt)
    string s = "Übung";
    if (s[0] == 'Ü')
    

    oder

    // benutze Encoding der Konsole (falls 850 dort eingestellt ist)
    const unsigned char UE = static_cast<unsigned char>(154);
    string s = std::string(1, (char)UE) + "bung";
    if (s[0] == UE)
    


  • @Quiche-Lorraine sagte in Probleme mit Umlauten:

    Aber zurück zum Thema: Ich verstehe die Sache mit dem Encoding der Konsole und dem Vergleich nicht. Was hat denn ein Vergleich der Form if (s[0] == UE) mit dem Encoding der Konsole zu tun?

    Der TE hat in seinem Code die Variable UE mit dem 'Ü' seiner Windows-Konsole belegt.
    Der String s beginnt aber mit dem 'Ü', wie es in der IDE codiert ist. Deshalb ist s[0] != UE
    Dieser Vergleich würde Sinn machen, wenn er "Übung" via cin von der Konsole eingelesen hätte, dann ergäbe der Vergleich true.

    Starte folgendes einfach mal aus der Konsole und gib ein großes 'Ü' ein:

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
       unsigned char IDE_UE = 'Ü';
       unsigned char CON_UE;
       
       cin >> CON_UE;
       
       cout << "IDE_UE: " << static_cast<int>(IDE_UE) << '\n';
       cout << "CON_UE: " << static_cast<int>(CON_UE) << '\n';
    }
    


  • @Th69 sagte in Probleme mit Umlauten:

    Also entweder:
    // benutze Encoding der Quellcodedatei (d.h. vom Compiler eingestellt)
    string s = "Übung";
    if (s[0] == 'Ü')

    Also etwa so? 🙂

    #include <iostream>
    
    using namespace std;
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("input.txt", "r", stdin);
    	freopen("output.txt", "w", stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    
    	const char AE = 'Ä';
    	const char ae = 'ä';
    	const char OE = 'Ö';
    	const char oe = 'ö';
    	const char UE = 'Ü';
    	const char ue = 'ü';
    	string s = "Übung";
    
    	if (s[0] == UE){
    		cout << "LALA";
    	}
    	/*cout << "Tüpfelhyäneöhrchenstraße\n";
    	printf("Coding of Ü: %i\n", static_cast<unsigned char>('Ü'));	
    	cout << "Coding of UE: " << static_cast<int>(UE) << "\n";
    	printf("Coding of s[0]: %i\n", s[0]);
    	printf("Coding of Ü (signed): %i\n", static_cast<char>('Ü'));*/
    
    	cout << AE << " " << OE << " " << UE << " " << ae << " " << oe << " " << ue;
    	return 0;
    }
    

    Achtung. Ich bin davon ausgegangen das ONLINE_JUDGE nicht definiert wurde, also das stdout Ausgaben nach output.txt umgeleitet werden.

    Der Trick hinter der Sache ist einfach folgender: Die CPP Datei wird in der gleichen Codepage gespeichert, mit welchem die Ausgabedatei output.txt standardmäßig interpretiert wird, mit der Systemcodepage.

    @Belli
    Verstehe ich.

    Ich glaube aber das Beispiel hat ein wenig verwirrt, da je nach definierten Präprozessor-Flag die Ausgabe auf der Console oder nach output.txt landet, im Code unterschiedliche Codierungen verwendet wurden und dadurch die if-Anweisung nicht funktionierte. Vermutlich hat mein erster Beitrag auch ein wenig dazu beigetragen, da ich erst einmal ein Testprogramm zeigte und danach meine Lösung.

    PS:
    Die if Anweisung funktioniert auch wenn ich die CPP Datei in Codepage 850 abspeichere.


Anmelden zum Antworten