Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Vergleichen von UnicodeStrings


ud11 - Do 13.01.11 13:01
Titel: Vergleichen von UnicodeStrings
Hallo zusammen,

zum Vergleichen von zwei WideStrings benutze ich die Funktion WideCompareStr. Diese liefert mir aber interessanter weise beim Vergleichen von "Cœur" (mit Ligatur) mit "Coeur" (ohne Ligatur) eine 0, was ja so viel bedeutet wie "gleich".

Das ist so eine Sache, immerhin ist der Text mit Ligatur ja nur 4 Zeichen, der ausgeschriebene 5 Zeichen lang...
(ä und ae sind ja schließlich auch nicht gleich)

Ich bin jetzt etwas verunsichert: Was mache ich kaputt, wenn ich statt dem WideCompareStr einfach den = Operator von Delphi benutze?

Bin für alle Hinweise, Anmerkungen und Tipps dankbar!
Uli


jaenicke - Do 13.01.11 13:28

Hallo und :welcome:

Ganz wichtig ist dabei erst einmal die Delphiversion. Ab Delphi 2009 sollten die Vergleiche auch bei normalen Strings, die Unicodetext enthalten, korrekt ablaufen. Und ich denke einmal, dass auch WideStrings noch einmal ggf. überarbeitet wurden.

Vorher habe ich es nicht ausprobiert.


BenBE - Do 13.01.11 15:26

Strings normalisieren und danach binär vergleichen.


ud11 - Do 13.01.11 15:46

Hi & danke für die superschnelle Antwort!

An der Delphi-Version liegt's nicht (getestet mit D2009), denn es wird ja lediglich die Windows-API Funktion "CompareStringW" (siehe SysUtils) aufgerufen. Das macht also quasi das Betriebssystem "falsch".

Wenn ich nur wissen muss, ob zwei Unicode-Strings *wirklich* gleich sind, gibt es da eine andere API-Funktion, die man dem Delphi "=" Operator vorziehen sollte?

Ich weiss, dass Unicode von vorne bis hinten ein "Grab" ist und mag mir nicht (noch) ein Eigentor schießen, deswegen habe ich etwas "Angst" vor dem "=" Operator, obwohl der in *diesem* Fall das richtige Ergebnis (nämlich ungleich) liefert!

Viele Grüße
Uli

Moderiert von user profile iconMartok: Doppelposting entfernt.

@Benny: Was meinst du mit "normalisieren"?


Delete - Do 13.01.11 22:32

Warm ist Unicode ein Grab? Was wäe denn deiner Meinung nach kein Grab?


bummi - Do 13.01.11 23:19

@Luckie

Strings aus einem IMMER 32 breiten CHAR, ich denke dann wären die Stringroutinen wieder um Welten schneller.


Delete - Fr 14.01.11 03:16

Richtig, aber alle Textdateien wären auf einmal vier mal so groß.


Tankard - Fr 14.01.11 06:01

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Warm ist Unicode ein Grab? Was wäe denn deiner Meinung nach kein Grab?


kann mir mal einer sagen was grap ist?
also ich kenne nur "crap"

gruss
tankard


Gausi - Fr 14.01.11 11:23

user profile iconTankard hat folgendes geschrieben Zum zitierten Posting springen:
kann mir mal einer sagen was grap ist?
also ich kenne nur "crap"


"Grab" ist ein gängiger deutscher Begriff. Aus der Wikipedia:
Zitat:
Das Grab ist die Begräbnisstätte für verstorbene Lebewesen. Es ist der Ort auf den sich der Totenkult der Kulturen bezieht.


ud11 - Fr 14.01.11 12:58

Ihr seid doof :-)

Unicode ist deswegen ein "Grab", weil man dadurch mehr Probleme bekommen hat als gelöst wurden :-) Aber von mir aus ist es auch "crap". Aber jetzt genug damit!

Habe noch eine Windows-API namens "CompareStringOrdinal" gefunden, die in meinem Fall anscheinend gut funktioniert. Leider gibt es diese erst ab Vista. D.h. für XP habe ich immer noch das Problem, verwende dort aber jetzt einfach den nativen "=" Operator. Bis jetzt sieht es gut aus. Aber das sah es zuvor ja auch, bis jemand mit den Ligaturen ankam. Ich bin daher gespannt, ob und wie es als nächstes Knallt.

Trotzdem Danke für's Zuhören


Martok - Fr 14.01.11 13:58

Und falls jemand die einzige sinnvolle Möglichkeit Text abzulegen die wir haben nicht nur als Grab sehen will, sondern verstehen will was hier warum passiert, so sei der OldNewThing-Artikel [http://blogs.msdn.com/b/oldnewthing/archive/2005/06/17/430194.aspx] zu NTFS FileSortOrder und die WP zu Collation [http://en.wikipedia.org/wiki/Collation]s empfohlen.

Welche Collation für den Vergleich verwendet wird, legt der erste Parameter von CompareStringW [http://msdn.microsoft.com/en-us/library/dd317759(VS.85).aspx] fest.

D7-RTL
1:
2:
3:
4:
5:
function WideCompareStr(const S1, S2: WideString): Integer;
{$IFDEF MSWINDOWS}
begin
  SetLastError(0);
  Result := CompareStringW(LOCALE_USER_DEFAULT, 0, PWideChar(S1), Length(S1), {...}


LOCALE_USER_DEFAULT ist also die Collation, die sich aus dem Gebietsschema ergibt. Auf einem PC mit DE_DE wird hier "Cœur" ordnungsgemäß umgeschrieben in "Coeur". Deutsch hat diese Ligatur nicht :!: . Stellt man das Gebietsschema auf FR, dann natürlich nicht mehr. Alternativ: CompareStrW mit LOCALE_INVARIANT aufrufen, wenn für den User unvorhersehbares (aber überall gleiches) Verhalten gewünscht ist.

Macht jedes DBMS übrigens genauso.


Delete - Fr 14.01.11 20:14

user profile iconud11 hat folgendes geschrieben Zum zitierten Posting springen:
Unicode ist deswegen ein "Grab", weil man dadurch mehr Probleme bekommen hat als gelöst wurden

Das ist Unsinn. Man muss nur wissen, wie man mit Unicode umzugehen hat. Ein Grab waren damals die Codepages für den ASCII-Zeichensatz, anstatt es gleich richtig zu machen. Hast du einen Text mit einer nicht deutschen Codepage bekommen, waren die Sonderbuchstaben im deutschen Alphabet alle Müll. Ich weiß nicht, wie alt du bist, aber ich habe die unsäglichen Zeiten mit den Codepages unter DOS noch am eigenem Leib erfahren.