Sonderzeichen in Programm vergleichen u. weiter verarbeiten



  • Hallo liebe Forenmitglieder,

    ich bin relativ neu in Sachen Programmierung und hänge an einem Problem mit Sonderzeichen fest. Ich muss in einem Programm eine Liste mit Worten verarbeiten in denen Sonderzeichen wie î, þ, ð u. a. vorkommen. Diese Zeichen sollen je nach Anwendungsfall von Kleinbuchstaben in Grossbuchstaben oder umgekehrt geändert werden.
    Speichere ich diese Strings in einem std::string ab kann ich sie auch richtig auf der Konsole wieder ausgeben lassen. Nur müsste ich diese Zeichen eines Strings auch verarbeiten können, das, was ich brauche klappt leider nicht:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    string a {"êl nîno"};
    string b {""};
    
    int laenge = a.size();
    int index {0};
    
    while(index < laenge) {
      char temp = a[index];
      if(temp == 'ê') temp = 'Ê';
      ++index;
      string b + temp;
    }
    
    cout << b << endl;
    return 0;
    

    anscheinend kann ich diese Sonderzeichen nicht in einer char-Variable ablegen und vergleichen.
    Zumindest habe ich herausgefunden dass auf meinem System ein char als ein signed char interpretiert wird. Ich nutze die Code::blocks IDE, in der wird unten ein
    UTF-8 angezeigt. Betriebssystem ist Ubuntu 20.04
    Wie ist hier der Weg um auch die Sonderzeichen als solche zu erkennen und mit Vergleichen arbeiten zu können?

    vielen Dank im Voraus
    Harry



  • Das schmerzloseste wäre wohl anstatt gegen einen char zu vergleichen, ein string zu vergleichen.

    Ich nehme mal an obiges ist nur ein Beispiel, sodass ich nicht direkt auf Einzelheiten eingehe, außer, dass die Codierung (utf-8, iso 86dingsbums, ...) bei Literalen glaube ich vom Editor abhängt den du verwendest, und man sich da nicht übergreifend drauf verlassen kann.
    Aber das könnte falsch sein.
    Ich gehe immer von UTF-8 überall aus, bis es nicht mehr stimmt und ich was machen muss 😃



  • Hallo 5cript,
    ich habe eine Liste mit > 40000 Strings zu bearbeiten. Es sollen ja nicht nur die Sonderzeichen bearbeitet werden können, auch die gängigen Literale sollten in Gross-/ Kleinbuchstaben gewandelt werden können.
    Der obige Code ist ein Beispiel mit dem ich annehme dass mein Problem verständlich rüber kommt. Tatsächlich ist die ganze Bandbreite von Sonderzeichen aus allen möglichen Sprachen verteten.

    Ich bin mir nicht ganz sicher was Du meinst mit "gegen einen String vergleichen" -

    string sonderZeichen {"Î"};
    // und dann kucken ob der String im basestring enthalten ist?
    

    lg!



  • Ja weil ein UTF-8 Zeichen variable länge haben kann.
    Ansonsten könntest du den kompletten String vorher in UTF codepages mit 4 byte breite umwandeln und dann das vergleichen.
    Wenn beide Strings aber die gleiche Codierung haben ist der Vergleich zweier std::string oder std::string_view am einfachsten.



  • Muss es C++ sein?
    Python + unidecode wäre ein einfacher und schneller Ansatz.

    Du musst zuerst mal wissen, in welchem Encoding deine Sonderzeichen vorliegen - und dann je nach dem handeln. In UTF-8 ist ein Buchstabe ein bis vier Bytes lang (variabel!) - in UTF-16 ist ein Buchstabe ein oder zwei 16-Bit-Wörter lang. Du musst also entsprechend eine Bibliothek suchen und dann mit dieser ersetzen, denn du willst ja nicht von Hand sämtliche Sonderzeichen pflegen!



  • Verwendest du schon C++11 (oder höher)? Dort gibt es u16string sowie u32string (s. std::basic_string), ansonsten mußt du wstring benutzen.

    Du kannst zwar UTF8-Texte in string halten, aber dann entspricht nicht ein einzelnes Byte einem Zeichen (sondern entsprechend 1-4 Bytes) und damit kannst du schlecht Texte vergleichen.

    Einen Überblick gibt es z.B. unter Unicode und Localization.

    Ab C++20 gibt es dann auch utf8string u8string. 😉



  • @Th69 sagte in Sonderzeichen in Programm vergleichen u. weiter verarbeiten:

    Verwendest du schon C++11 (oder höher)? Dort gibt es u16string sowie u32string (s. std::basic_string), ansonsten mußt du wstring benutzen.

    Auch in UTF-16 gibt es Code Points die mit mehreren (in diesem Fall 16 Bit breiten) Code Units kodiert werden. Auch hier entspricht str[i] nicht (immer) dem, was die meisten Leute unter einem "Zeichen" verstehen. In UTF-32 übrigens auch nicht bei genauerer Betrachtung ...

    Du kannst zwar UTF8-Texte in string halten, aber dann entspricht nicht ein einzelnes Byte einem Zeichen (sondern entsprechend 1-4 Bytes) und damit kannst du schlecht Texte vergleichen.

    ... was daran liegt, dass es "Zeichen" gibt, die zwar als einzelne Einheit dargestellt werden, sich jedoch aus mehreren Code Points zusammensetzen. So lässt sich z.B. selbst ein unschuldig wirkendes Sonderzeichen wie ä in so darstellen, dass es in jeder (!) Unicode-Codierung mehr als einen CharT einnimmt (char, char8_t, char16_t oder char32_t):

    a (U+0061 Kleiner lateinischer Buchstabe A) + ̈ (U+0308 Verbindungszeichen Diärese) = ä (U+00E4 Kleiner lateinischer Buchstabe A mit Diärese)

    Um die Verwirrung komplett zu machen gibt es für das ä mit U+00E4 natürlich auch noch einen eigenen Code Point was z.B. korrekt implementierte Textvergleiche nicht gerade trivial macht. Eigentlich müsste man zu vergleichende Texte erstmal in eine kanonische Darstellung überführen ("normalisieren").

    @HarryS_79 Dein Problem kann man beliebig detailliert lösen. Wie genau brauchst du es? Die simpelste Lösung dürfte wohl tatsächlich sein, die Strings nach wstring zu überführen, obengenannte Bedenken einfach zu ignorieren und mittels std:towupper die Gross/Kleinschreibung-Konvertierung durchzuführen. Das wäre keine absolut korrekte Lösung und eventuell auch system-/implementierungsabhägig, ist aber mit C++-Hausmitteln ohne externe Unicode-Bibliotheken machbar und täte zumindest für westliche/europäische Sprachen meistens das was es soll (von Dingen wie ß -> SS mal abgesehen - siehe std:towupper).

    Einen Überblick gibt es z.B. unter Unicode und Localization.

    Ab C++20 gibt es dann auch utf8string. 😉

    Ist ein std::u8string nicht nur ein std::basic_string<char8_t>? Man möge mich korrigieren, aber ich kann da keinen signifikanten Unterschied zu seinem std::string a.k.a std::basic_string<char> erkennen, der einem den Umgang mit UTF-8 erleichtert - abgesehen davon, dass der eigene Typ deutlich macht, in welcher Codierung der String vorliegt. Was es da haupstächlich bräuchte wären eine Reihe Hilfsfunktionen direkt in der Standardbibliothek. z.B. sowas wie std::unicode_normalize oder ein std::toupper(u8string). Wenn ich da nicht etwas wichtiges übersehen habe, kann man das aber wohl erstmal knicken und braucht externe Bibliotheken für sowas.



  • erstmal vielen Dank an alle für die Erklärungen!

    ich werde mich nun daran machen alle Posts durch zu arbeiten. Meine Kenntnisse beziehen sich momentan noch auf die Grunddatentypen wie char und string, wstring und ähnliches sind mir noch nicht geläufig. Auch die genannten Funktionen std::toupper werde ich mir erst ansehen müssen.

    Ich habe nur noch eine Zwischenfrage zum Verständnis:
    Bei allen Versuchen ist es doch bestimmt auch wichtig, verschiedene Zeichentabellen auf dem System auszuprobieren, oder? Momentan ist systemweit UTF8 eingestellt. Bringt es in diesem Falle auch was mit ISO 8859-1 zu probieren?
    Meine gestrigen Bemühungen, Ubuntu auf global ISO 8859-15@euro umzustellen waren nicht besonders erfolgreich, z.B. lies sich das Terminal nicht mehr öffnen. Also müsste ich mich da auch noch mehr in die Thematik einlesen.

    viele Grüße und schonmal vielen Dank!



  • @HarryS_79 sagte in Sonderzeichen in Programm vergleichen u. weiter verarbeiten:

    Bei allen Versuchen ist es doch bestimmt auch wichtig, verschiedene Zeichentabellen auf dem System auszuprobieren, oder?

    Nein, es ist entscheidend, in welcher Kodierung die Texte in der Datei gespeichet wurden.


Log in to reply