C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum
-
@Mullins182 sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
Ja, ich bin sicher das Windows 1252 Codepage aktiv ist.
Das war nicht meine Frage. Meine Frage war, in welcher Kodierung die Datei gespeichert ist.
Wie gesagt, mit einem Debugger oder einem
std::cout << buffer[i] << " - code: " << ((int)(buffer[i])) << '\n';
sollte sich das Problem doch schnell rausfinden lassen.Würde dennoch davon abraten, 228 direkt so ins Programm zu schreiben.
-
@Mullins182 sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
(int)buffer[i] == 228
Das wird so nix werden.
char
ist üblicherweise signed. D.h. alschar
ist der Wert für CP 1252ä
nicht 228 sondern -28.
-
Ach so. Hatte ich missverstanden. Die Datei mit der Wortliste die in Großbuchstaben umgewandelt werden soll ist mit UTF-8 kodiert, hab ich gerade gesehen. Ich hoffe man kann irgendwie mit 'ofstream' die Kodierung angeben in welcher die Datei erstellt wird .... Hab noch nicht so viel Erfahrung bisher.
Hier ist ein Wort aus der Datei welches 'ä' enthält und mit Deinem Code aus 'buffer' ausgelesen wurde :
G - code: 71 a - code: 97 l - code: 108 g - code: 103 e - code: 101 n - code: 110 m - code: 109 Ã - code: -61 ¤ - code: -92 n - code: 110 n - code: 110 c - code: 99 h - code: 104 e - code: 101 n - code: 110
-
Hallo,
da hast du dir als C++ Anfänger gleich eines der schwierigsten Themen ausgesucht (nämlich das Encoding).
Für Linux würde man "all is UTF-8" verwenden, unter WIndows ist das (sehr viel) komplexer: Unicode part 2: UTF-8 stream mode (ich hoffe, du kannst ein wenig englisch?).
Mitchar
undstd::string
funktioniert es nicht, da damit nur (erweitertes) ASCII möglich ist, so daß für Unicode die 'wide'-Datentypen und Funktionen benötigt werden.
Einfacher wäre es daher für dich, wenn du die Datei als "ANSI" (d.h. erweitertes ASCII) speicherst, so daß du deinen Code dann so lassen kannst.PS: Ist es so gewollt von dir, daß du die Formatierung der Datei änderst, nämlich mit
read >> buffer
nur Wörter (ohne Leerzeichen) einliest und diese dann jeweils zeilenweise wieder zurückschreibst?
Besser wäre sonst einfach zeichenweise einzulesen.
-
Hallo zurück.
Ja, das ist so gewollt. Ich habe ein Galgenraten Spiel geschrieben und das Programm braucht eine Wortliste aus Großbuchstaben welche alle untereinander geschrieben sind. Ja, ich kann auch englisch ^^
Die Wörter in der Quelldatei sind auch untereinander geschrieben.
Das Programm aus dem der Code ist welchen ich gepostet habe, wandelt alle Wörter der Quelldatei in Großbuchstaben um, nur Umlaute halt nicht. Kennst Du vielleicht eine einfache Methode um Umlaute von Wörtern aus einer Datei (UTF-8 codiert) in Großbuchstaben umzuwandeln und diese dann in die Zieldatei zu schreiben ?
-
Was erhoffst du dir wenn du "ofstream" sagst welche kodierung vewendet werden soll?
ofstream verwendet char als datentyp für ein einzelnes "Zeichen" wobei das nur für single byte kodierungen wie ASCII/ANSI gilt. AFAIK macht ofstream hier keine Konvertierung.UTF-8 ist eine Kodierung wo ein Zeichen aus bis zu 4 bytes bestehen kann.
Da ist es besser, wenn deine Einleselogik mit UTF-8 klar kommt statt die Kodierung der Ausgabe zu verändern.
-
Richtig ... war auch ein Irrtum meinerseits. Natürlich soll ifstream mit UTF-8 klar kommen.
-
@Mullins182 sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
Hallo zurück.
Ja, das ist so gewollt. Ich habe ein Galgenraten Spiel geschrieben und das Programm braucht eine Wortliste aus Großbuchstaben welche alle untereinander geschrieben sind. Ja, ich kann auch englisch ^^
Die Wörter in der Quelldatei sind auch untereinander geschrieben.
Das Programm aus dem der Code ist welchen ich gepostet habe, wandelt alle Wörter der Quelldatei in Großbuchstaben um, nur Umlaute halt nicht. Kennst Du vielleicht eine einfache Methode um Umlaute von Wörtern aus einer Datei (UTF-8 codiert) in Großbuchstaben umzuwandeln und diese dann in die Zieldatei zu schreiben ?Eine "standard" C library für unicode ist ICU (https://unicode-org.github.io/icu-docs/#/icu4c/)
Für einen "C++ " Wrapper kannst du Boost.Locale verwenden.Du hast nicht nur ein Problem mit dem "mache alle Buchstaben zu Großbuchstaben" auch in deinem eigentlichen Spiel wirst du auch Probleme mit nonascii zeichen haben (wie die Umlaute).
Denn, wie schon gesagt, gilt bei UTF8 nicht mehr das ein byte (codepoint) = ein Zeichen ist.
Denn scheinbar gehst du davon aus das "ein byte (codepoint)" = "ein Zeichen" ist.Selbst für UTF-16, was windows für seine Unicode API (wide char) nutzt, gilt das nicht, wenn man alle UNICODE zeichen mit in die Betrachtung einbezieht.
Erst mit UTF-32 kann man aktuell sagen, dass ein codepoint = ein Zeichen gilt.
Wobei das auch nur die halbe Wahrheit ist.
In Unicode gibt es auch die Möglichkeit ein Zeichen aus mehreren unicode Zeichen zusammen zu setzen (https://unicode.org/faq/char_combmark.html)Ein Beispiel. Der Buchstabe "ä" kann einmal als "ä" (UNICODE: U+00E4) dargestellt werden oder als "a" + "<zwei punkte oberhalb>" (UNICODE: a (U+0061) - ◌̈ (U+0308))
https://www.compart.com/en/unicode/U+00E4UNICODE ist ein komplexes thema um das ganze korrekt selbst umzusetzen.
Die Frage ist für welche Sprachen möchtest du in deinem Spiel unterstützen?
Wenn das jetzt nur deutsch und englisch ist, dann könnte man auch überlegen dass intern UTF-16 genutzt wird, da für diese beiden Sprachen das ein UTF-16 codepoint = ein Zeichen gilt.Und eine Konvertierung zwischen den verschiedenen UTF kodierungen ist sehr einfach. Und AFAIK seit C++11(?) gibt es in der c++ standard library funktionen für diese Konvertierung.
In den meisten Text-Editoren werden die Deutschen Umlaute auch nicht in ihrer "Decomposition" form gespeichert (wenn man den text z.b. als UTF-8 speichert, wodurch man diesen spezialfall hier auch ignorieren kann.
Oder du verzichtest komplett auf umlaute und bleibst im ASCII bereich.
Ein 'ä' würde dann als 'a''e' Dargestellt werden
-
Okay, danke für die Info`s ... Ich glaube ich werde lieber auf Umlaute verzichten in dem Programm
-
@Mullins182 sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
Okay, danke für die Info`s ... Ich glaube ich werde lieber auf Umlaute verzichten in dem Programm
Wenn es dir darum geht c++ zu lernen ist das eine gute alternative diese Problematik erst mal zu vermeiden.
Wenn es dir aber eher darum geht das Spiel umzusetzen und die verwendete Programmiersprache eher nebensächlich ist, dann wäre die Nutzung einer Sprache besser geeignet, welche für String schon einfacher nutzbaren Support für UNICODE hat.
z.b. C#/Java oder Python.
C# z.b. nutzt intern UTF-16 für Strings.
-
Auch gut zu wissen, dass C# UTF-16 nutzt ... Ich mache eine Umschulung in einer Computerschule und wir haben gerade die Grundlagen von C++ gelernt. Mit C# fangen wir demnächst an ... ich warte dann wohl noch bis ich das Spiel in C# programmieren kann bevor ich Wortlisten mit Umlauten nutze. Aber das Spiel ist schon fertig. Die Wortliste enthält aber im Moment nur 50 Wörter und die stocke ich dann jetzt mit umlautlosen Wörtern auf, bis ich das Programm mit C# neu geschrieben habe.
Vielen Dank für die Hilfe und ein schönes Wochenende weiterhin ^^
-
Ich wiederhole mich einfach mal:
@Th69 sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:Einfacher wäre es daher für dich, wenn du die Datei als "ANSI" (d.h. erweitertes ASCII) speicherst, so daß du deinen Code dann so lassen kannst.
Einfach die Datei mit Notepad laden und dann mit "Speichern unter..." als Codierung "ANSI" wählen (d.h. das entspricht dann der Code Page Windows-1252).
-
Okay, vielen Dank ... Das werde ich ausprobieren ...
-
Sobald du mit C# anfängst, kannst du dann ja mal ein bißchen mit der Encoding-Klasse herumspielen.
-
@firefly sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
Denn, wie schon gesagt, gilt bei UTF8 nicht mehr das ein byte (codepoint) = ein Zeichen ist.
Denn scheinbar gehst du davon aus das "ein byte (codepoint)" = "ein Zeichen" ist.Selbst für UTF-16, was windows für seine Unicode API (wide char) nutzt, gilt das nicht, wenn man alle UNICODE zeichen mit in die Betrachtung einbezieht.
Erst mit UTF-32 kann man aktuell sagen, dass ein codepoint = ein Zeichen gilt.Darf ich ein bisschen korinthenkacken? Das Byte oder den
char16_
/char32_t
nennt man Code Unit. Eines oder mehrere davon kodieren einen Code Point im Unicode (z.B. dasä
, dasa
oder das ◌̈).Oder hab ich dich nur falsch verstanden?
-
@Finnegan sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
@firefly sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
Denn, wie schon gesagt, gilt bei UTF8 nicht mehr das ein byte (codepoint) = ein Zeichen ist.
Denn scheinbar gehst du davon aus das "ein byte (codepoint)" = "ein Zeichen" ist.Selbst für UTF-16, was windows für seine Unicode API (wide char) nutzt, gilt das nicht, wenn man alle UNICODE zeichen mit in die Betrachtung einbezieht.
Erst mit UTF-32 kann man aktuell sagen, dass ein codepoint = ein Zeichen gilt.Darf ich ein bisschen korinthenkacken? Das Byte oder den
char16_
/char32_t
nennt man Code Unit. Eines oder mehrere davon kodieren einen Code Point im Unicode (z.B. dasä
, dasa
oder das ◌̈).Oder hab ich dich nur falsch verstanden?
Eher das ich die beiden begriffe durcheinander geschmissen habe
-
Werd ich machen
Vielen Dank für den Tipp die Source-Datei in ANSI umzuwandeln. Nun musste ich nur noch die Bedingung der If-Abfrage anpassen und habe jetzt großgeschriebene Umlaute in meiner Wortliste ....
Schönen Feiertag morgen ...
-
Wieso denn nicht so ... um das "if"-Geraffel zu vermeiden?
/** * Reads data from a file and writes the modified data to another file. * * @param filename The name of the file to read from. * * @return void * * @throws None */ void readFromAndWriteToFile(std::string filename) { std::unordered_map<char, char> replaceMap; for (auto &c : std::vector<char>{(char)228, (char)246, (char)252}) { replaceMap[c] = c - 32; } // replaceMap[228] = 228 - 32; // replaceMap[246] = 246 - 32; // replaceMap[252] = 252 - 32; std::ifstream infile(filename); std::ofstream outfile(filename + ".out"); std::string line; while (std::getline(infile, line)) { for (int i = 0; i < line.size(); i++) { if (replaceMap.find(line[i]) != replaceMap.end()) { line[i] = replaceMap[line[i]]; } } outfile << line << std::endl; } }
(Edit: Zum Teil AI-generiert ...)
-
@wpi sagte in C++ | If-Abfrage funktioniert nicht und ich weiß nicht warum:
Wieso denn nicht so ... um das "if"-Geraffel zu vermeiden?
2 Nachteile:
a) (fast irrelevant, aber aus Prinzip)map.find(x)
gefolgt vonmap[x]
ist doppelte Arbeit. Gleich das Ergebnis von find speichernauto it = map.find(x)
und beiit != end
direkt verwenden (*it
) spart 1 Lookup.
b) (wesentlich) das funktioniert nur unter der Annahme, dass alle Zeichen in 1 char passen. Was ist mit Unicode und verschiedenen Kodierungen? Bei UTF-8 müsstest du z.B. variabel viele chars ersetzen, je nach Länge des Zeichens. (um fair zu sein, das Problem hat der Ursprungscode auch)
-
Gefällt mir.
Ich lasse das mal refactoren. Codeium kann Funktionen auch vollautomatisch refactoren und mit Kommentaren versehen...
Aber erst später, denn bin gerade unterwegs und schreibe Handy.
Edith: Codeium ist free und gibt es als Erweiterung für viele IDEs... hätten wir doch damals nur diesen Luxus gehabt...