Zeichenkette vergleichen



  • Das grosse ß ist in Unicode "relativ neu" (2008).
    Und bei der Umwandlung des kleinen ß in Grossbuchstaben wird weiterhin ein doppel-S generiert.

    Ein korrekt implementierter Vergleich macht zwar keine Umwandlung, aber nicht alles ist immer korrekt implementiert. Und dann ist noch die Frage welchen Unicode-Standard die Vergleichsfunktionen verwenden.

    also was machen?

    Pfuh, ja, gute Frage. Du könntest versuchen die ICU einzubinden (International Components for Unicode). Die bringt eigene Datensätze mit und muss sich daher nicht auf irgendwas vom System verlassen. Was aber auch ein Nachteil ist, denn dadurch musst du die Anwendung immer updaten wenn neue Unicode-Versionen rauskommen - anstatt dass es über ein OS-Update "automatisch" funktioniert.

    Was du sonst noch probieren könntest wäre die WinAPI direkt zu verwenden (ich nehme auf Grund des ShowMessage in deinem Code mal an dass du Windows verwendest):
    https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringw
    https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringex



  • @hustbaer sagte in Zeichenkette vergleichen:

    Was du sonst noch probieren könntest wäre die WinAPI direkt zu verwenden

    @Gestalt Das wäre neben ICU tatsächlich empfehlenswert, da diese Funktionen nicht nur einen case-insensitiven Vergleich, sondern auch einen mit Unicode-Normalisierung machen können. Es gibt nämlich für etliche eigentlich "gleiche" Zeichen mehrere Unicode-Repräsentationen, so dass man keinen einfachen Bit-Vergleich machen kann, auch wenn man das Problem der Groß/Kleinschreibungs-Umwandlung bereits gelöst hat. Z.B. kann ein "ä" direkt als dieses Zeichen codiert werden, oder als ein "a" mit einem "Verbindungszeichen" für doppelte Punkte darüber:

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

    Sowas gilt es jedenfalls zu beachten, sofern es für den Anwendungsfall relevant ist und man es wirklich korrekt hinbekommen will.



  • @omggg Anwendungsfall ?, ja das ist eben alles so eine Sache, ich hab einfach von vielen Dingen kein ausreichendes Hintergrundwissen, bin eigentlich auch komplett überfordert mit dem C++ Kram, wenn man irgendwann merkt das alles nicht ganz so funktioniert wie man vermutet dann nervt es einfach nur noch. Meine Problem ist das ich vieles gegenteste weil es perfekt funktionieren soll und das macht mich fertig, nicht gleich aber über viele Jahre hinweg schon. Selbst wenn eine Aktion noch so absurd erscheint, probiere ich diese durch und dabei wird man Irre, weil ein Befehl am Ende dann doch komplett unbrauchbar ist, und davon gibt es eine Menge. Ich hätte gerne für StringVergleiche die STL benutzt aber wenn es nicht perfekt funktioniert dann ist es für mich unbrauchbar. Ich könnte Dir jetzt explizit Beispiele nennen die mich unglücklich machen weil es einfach nicht funktioniert wie erwartet. Bei dem ist dies beim ist das und wenn Du das machst dann passiert das und und und . Ich kann nicht mehr - Ich habe die Schnauze voll.



  • @Gestalt sagte in Zeichenkette vergleichen:

    Anwendungsfall ?, ja das ist eben alles so eine Sache,

    genau. Ist zum Beispiel bei dir I == i? Oder hast du auch türkische Wörter im Text, wo I == ı ist (und İ == i). Wie willst du das zählen? Das ist nicht immer so klar.

    Außerdem ist noch die Frage, in welchem Encoding dein Sourcecode denn ist... Das kann durchaus auch relevant sein. Google mal nach finput-charset und erfreue dich der Resultate.



  • @hustbaer Danke für die Info. Bisher bin ich hiermit immer ganz gut gefahren, aber ich probiere eben auch gern andere Dinge aus.

    int __fastcall AnsiCompareText(const System::UnicodeString S1, const System::UnicodeString S2)
    


  • @Gestalt
    Ist das Delphi?
    Soweit ich weiß ist ein UnicodeString UTF-16 kodiert und du kannst ihn ohne Probleme einem std::wstring zuweisen:

    UnicodeString u = L"Wer weiß denn sowas?";
    std::wstring const w = u.c_str();
    

    Vielleicht kommste damit weiter.

    Hab bisher nur wenig mit UTF zu tun gehabt, meiner Meinung nach kann man mit UTF8 nicht arbeiten, das ist eher ein Transportprotokoll, um Textdaten auszutauschen. Wir machen das so, dass wir intern mit std::wstring arbeiten, damit wir solche Probleme wie von @Finnegan beschrieben nicht haben.



  • @wob also das Encoding ist UTF-8 und in den Optionen unter Codepage ist kein Eintrag



  • Dieser Beitrag wurde gelöscht!


  • @DocShoe sagte in Zeichenkette vergleichen:

    Hab bisher nur wenig mit UTF zu tun gehabt, meiner Meinung nach kann man mit UTF8 nicht arbeiten, das ist eher ein Transportprotokoll, um Textdaten auszutauschen. Wir machen das so, dass wir intern mit std::wstring arbeiten, damit wir solche Probleme wie von @Finnegan beschrieben nicht haben.

    Und wo soll das irgendwas davon beheben? Wie hilft wstring dabei?
    Ich finde https://utf8everywhere.org/ sehr hilfreich, es fasst die Argumente gut zusammen.



  • @DocShoe Es gibt auch Fälle wo ich das so mache um einfach mit der STL zu arbeiten. Nur Im Grunde reduziere ich es auf WideString, wchar_t*, da viele Funktionen genau diesen Datentyp erwarten.



  • @wob sagte in Zeichenkette vergleichen:

    @DocShoe sagte in Zeichenkette vergleichen:

    Hab bisher nur wenig mit UTF zu tun gehabt, meiner Meinung nach kann man mit UTF8 nicht arbeiten, das ist eher ein Transportprotokoll, um Textdaten auszutauschen. Wir machen das so, dass wir intern mit std::wstring arbeiten, damit wir solche Probleme wie von @Finnegan beschrieben nicht haben.

    Und wo soll das irgendwas davon beheben? Wie hilft wstring dabei?

    Hab den Eindruck, dass @Gestalt das mit C++ lösen möchte. Ansonsten verstehe ich den ganzen Thread hier nicht, weil AnsiCompareText ja angeblich funktioniert.



  • @DocShoe sagte in Zeichenkette vergleichen:

    Hab den Eindruck, dass @Gestalt das mit C++ lösen möchte.

    Mir ging es um deine Aussage, dass ihr intern einfach wstring nehmt und dann keine Probleme hat. Und das verstehe ich nicht, weil die Probleme doch genauso auftreten. Auch wstring kennt nicht unicode, sondern ist einfach nur eine Aneinanderreihung von mindestens 16 Bit breiten chars. Wie löst das Finnegans Problem, dass ein Zeichen mehrere Darstellungen haben kann? Nicht alle Zeichen passen in ein 16-Bit-wchar. Und so weiter. Deine Aussage war, dass man utf8 nur als Transport gebrauchen kann. Aber ich sehe das nicht.

    Edit: das CompareStringW wurde ja schon genannt, sofern man auf Windows ist.



  • @DocShoe Es funktioniert sehr gut über diese Funktionen auch gibt es Gebietschemaunabhängigen Funktionen IC ich glaube so rum war es , die funktionieren auch sehr gut und auch _TCHAR geht auch alles gut, Beispiel wäre hier _tcsicmp , geht alles , nur wollte ich es über die STL oder BOOST Funktionen bewältigen und zwar auf einfache Art und Weise, aber leider geht es nicht - ja und ich bin auch zu blöd dafür. Was macht jemand der die STL oder Boost benutzt in dem Fall? siehe Ausgangspost. Muss ja ne Lösung geben. Ohne ständig die Bibliotheken zu wechseln.



  • @wob

    Unsere Software ist nicht 100% kompatibel mit allen möglichen UTF-16 Codepoints, wir gehen davon aus, dass sich alle Zeichen als 16bit-Zeichen in der aktuell verwendeten locale darstellen lassen, bzw. wir unterstützen nur solche Sprachen, die diese Bedingung erfüllen.
    UTF8 wird an der Stelle sperrig, wo man auf einzelne Codepoints zugreifen möchte. So Sachen wie

    utf8string utf8 = "Last äkschn Hero";
    utf8[4] = 'Ä' 
    
    oder
    std::reverse( utf8.begin(), utf8.end() );
    

    werden plötzlich kompliziert. Mit std::wstring gibt's diese Probleme nicht mehr, zumindest nicht in unserer Software.
    Vielleicht haben wir die Probleme auch nur, weil wir gewachsene Software mit "konventioneller" String-Behandlung haben, wenn man das modern machen wollte müssten wir vermutlich alles, was irgendwie mit Strings zu tun hat, anfassen.

    Edit:
    Damit unterstützt unsere Software natürlich keine alt-chinesische Kalligraphien. Aber das ist für uns auch nicht wichtig und nicht gefordert.



  • @DocShoe sagte in Zeichenkette vergleichen:

    Wir machen das so, dass wir intern mit std::wstring arbeiten, damit wir solche Probleme wie von @Finnegan beschrieben nicht haben.

    Auch mit std::wstring und sogar mit 32-Bit Code Units wird man immer noch das Problem mit der Normalisierung haben. Es kann natürlich sein, dass die verarbeiteten Strings alle aus einer Datenquelle stammen, wo diese bereits normalisiert sind (das ist vermutlich der Fall, wenn man nur Strings verarbeitet, die z.B. alle aus einem RDBMS kommen). Oder die Daten wurden alle auf die selbe Art eingegeben (ich tippe, dass z.B. ein Windows-Eingabefeld ein ä immer direkt als diese Zeichen und nicht als a mit Verbindungszeichen erzeugt). Gut möglich, dass das Problem einfach noch nicht aufgetreten ist. oder Zumindest nicht so, dass es aufgefallen wäre. Man braucht halt auch erstmal zwei Strings mit unterschiedlichen Codierungen des selben Zeichens.

    Was das "ein Zeichen, ein String-Index" angeht, so funktioniert das mit wstring wahrscheinlich auch häufig. Zumindest für Zeichen aus der Basic Multilingual Plane, die schon eine ganze Menge abdeckt. Aber streng genommen ist das ja auch eine UTF-Format, bei dem ein Zeichen aus mehreren Codepoints bestehen kann. Genau wie bei UTF-8 auch. Wenn man also Unicode vollständig unterstützen will, muss man das sowieso auch mit UTF-16 genau so wie bei UTF-8 berücksichtigen. Das ist auch eines der Argumente von utf8everywhere.org, dass man da auch gleich UTF-8 nehmen kann.

    Von dem, was ein "Zeichen" ist, und dass die auch mit 32-Bit-Codierung mehr als ein Codepoint und damit mehr als einen String-Index haben können fange ich besser nicht an.
    Aber man kommt durchaus auch mit wstring durch, solange man auf keine Sonderfälle stößt. Es ist halt nur leider nicht vollständig korrekt.



  • @DocShoe sagte in Zeichenkette vergleichen:

    Vielleicht haben wir die Probleme auch nur, weil wir gewachsene Software mit "konventioneller" String-Behandlung haben, wenn man das modern machen wollte müssten wir vermutlich alles, was irgendwie mit Strings zu tun hat, anfassen.

    Ja, das wird denke ich ziemlich kompliziert. Ich sehe auch noch viel "gewachsene" Software, die z.B. noch Probleme mit Umlauten hat. Gerade kürzlich wieder in einer Autodesk-Software gesehen bei der Benennung von Objektgruppen.

    Eigentlich müsste man auch einzelne "Zeichen" immer als Substring handhaben. Direkter Index-Zugriff ist da nicht möglich, außer mit einer speziellen String-Datenstruktur die Zeichen-Positionen auf String-Indizes mappt. Das ist immer Suchen+Substring-Operation. Selbst den Index eines "Zeichens"¹ (bzw. "Graphem-Cluster" oder wie auch immer man Zeichen definiert muss man erst "suchen").

    ¹ Ich hatte ja vor einiger Zeit mal ein Beispiel gebracht wie übel das mit den "Zeichen" in Unicode theoretisch werden kann: https://www.c-plusplus.net/forum/topic/353091/sollte-man-heute-mehr-wstring-anstellen-von-string-einsetzen/17. Dass der Browser das überhaupt korrekt rendern, man da beim Text-Markieren auch tatsächlich ganze "Zeichen" intuitiv auswählen und mit der Textsuche sogar mit einem Suchstring ohne die ganzen Akzente den Text finden kann, zeigt schon, wie viel zum Handling von Unicode-Text dazu gehört.



  • @Finnegan allerdings

    UTF8String utf8 = U"Last äkschn Hero";
    utf8.Insert(U"Ä", 4);
    //utf8[4] = 'Ä'; ergibt nur Müll
    ShowMessage( utf8);
    


  • @Gestalt
    Das ist das Tolle an UTF8, die ersten 127 Zeichen sind ASCII und damit kompatibel zu allem, was mit ASCII umgehen kann.



  • @omggg Ein Anwendungsbeispiel und zwar eins wo ich sage das wird niemals passieren aber daran erkennst Du das ein Vergleich über die STL nicht perfekt funktioniert.

    Du wolltest es so 😀

    Dein Programm welches in die Windows-Registry folgendes schreibt "C:\Toolß\test.exe" um einen Autostart zu bewältigen wenn Windows gestartet wird.
    Die test.exe wird gestartet und ließt sogleich aus der Registry diesen Pfad aus und vergleicht diesen mit ihren eigenen Pfad, also "C:\Toolß\test.exe".
    Der Vergleich ist TRUE und in den Optionen der test.exe wird eine CheckBox gesetzt die den Anwender zeigt - ich werde automatisch gestartet.

    Nun, weil ich ja nix anderes zu tun habe als zu testen und lange Weile habe ändere ich auf der Festplatte den Ordnernamen von "Toolß" nach "Toolẞ" um.

    Beim nächsten Windows-Neustart startet wie gewohnt die "test.exe", sie ließt aus der Registry den unveränderten Eintrag "C:\Toolß\test.exe" aus.
    Der Vergleich per STL oder Boost schlägt diesmal aber fehl und in den Optionen der test.exe wird die Checkbox nicht gesetzt und dem Anwender gezeigt das dieses Programm nicht automatisch mit Windows startet.



  • @DocShoe sagte in Zeichenkette vergleichen:

    wir gehen davon aus, dass sich alle Zeichen als 16bit-Zeichen in der aktuell verwendeten locale darstellen lassen

    na dann... füg doch mal einen Violinschlüssel ein, weil du was mit Musik machen willst. Ach, geht nicht?

    Das ist ja genau das Argument, warum wstring eben nicht die Lösung sind. Sie laden zu solchen "halbrichtigen" Lösungen ein. Nehmt doch einfach ASCII und chars. Das ist dann "viertelrichtig"? 😉


Anmelden zum Antworten