Einzelnen Beitrag anzeigen

Benutzerbild von toms
toms
(CodeLib-Manager)

Registriert seit: 10. Jun 2002
4.648 Beiträge
 
Delphi XE Professional
 

Widechar Sets für Unicode (Delphi 2009)

  Alt 26. Feb 2009, 20:36
Hallo

Ich denke den einen oder anderen könnte der Artikel "Widechar sets for Unicode" von P. Below, welcher im forums.codegear veröffentlicht wurde, interessieren.

Assertor war so freundlich, und hat den Artikel ins Deutsch übersetzt. Herzlichen Dank!

Delphi 2009 hat nun endlich den vollständige Wechsel zu Unicode geschafft, der Standard-Stringtyp ist nun ein Unicode-String und Char ist ein WideChar (16 bit). Eins der Opfer dieser Änderungen ist die gute alte Praxis die Eingabedaten mit Ansätzen wie folgt zu prüfen:

if Key In ['0'..'9'] then ....

Da in Delphi ein set maximal 256 Elemente haben kann, ist ein set of Char nicht länger möglich. Stattdessen wird ein set wie oben genannt als set of Ansichar (TSysCharset) kompiliert und der Quellcode (mit Key als Datentyp Char) erzeugt eine Warnung. Das funktioniert solange Key in dem Bereich von #0 bis #127 ist (dem 7-bit ASCII Bereich), aber das Ergebnis ist undefiniert wenn dies nicht der Fall ist.

Was können wir nun als Gegenstück verwenden? Delphi bietet die CharInSet Funktion, die zumindest die Warnung unterdrückt aber ebenfalls für alle Zeichen oberhalb von #127 versagt. Das nutzt vielleicht Amerikanern aber nicht dem Rest der Welt <g>.

Die WidechatSetU-Unit in diesem Archiv (Download bei cc.codegear.com) zielt darauf ab dieses Problem zu lösen, in dem ein Gegenstück zu set of WideChar geboten wird. Die Verwendung ist etwas abweichend von dem klassischem set, da es keine eingebaute Kompilerunterstützung für "widechar set" gibt und die Programmiersprache auch keine Unterstützung für überladene Operatoren in Interface-Typen enthält (wobei ich Interfaces als Basis für die Implementation gewählt habe).

Ein üblicher Test wie

if Key In ['0'..'9'] then ....

würde nun so durchgeführt

if Digits.Contains(Key) then ...

Dies nutzt eine der vordefinierten widechar sets. Die Sets sind Singletons, so daß deren Nutzung einen geringen Overhead erzeugt. Wenn Ihr ein eigenes set erzeugen müsst, funktioniert dies mit Hilfe der WidecharSets Factory:

if Key in ['0'..'9', 'a'..'z', 'A'..'Z', '$'] then ...

würde zu

if Widecharsets.Create(['0'..'9', 'a'..'z', 'A'..'Z','$']).Contains(Key) then Da dies für jeden Aufruf ein neues widechar set erzeugen würde, wäre es effizienter das set einmalig zu erstellen und für die Lebenszeit des Objekts in dem der if Test enthalten ist zu behalten. Der Konstruktor (oder der OnCreate-Event des Formulars) wäre ein guter Platz dafür:

Delphi-Quellcode:
// Objektfeld
FAllowedChars: IWidecharSet;

// Konstrukturaufruf
FAllowedChars := Widecharsets.Create(['0'..'9', 'a'..'z', 'A'..'Z','$']);
Damit würde der Test zu

if FAllowedChars.Contains(Key) then Da die Lebenszeit der widechar sets über die Interface-Referenzzählung gesteuert wird, muß man sich nicht selbst darum kümmern, daß der von diesen genutze Speicher freigegeben wird wenn sie nicht mehr gebraucht werden.

Die Erzeugung eines widechar set mit Eingabedaten in Form eines set von ANSI Zeichen funktioniert auch, selbst wenn das ANSI-set Zeichen über #127 enthält. Die Widecharsets.Create Methode, die das set als Eingabedaten entgegen nimmt (widechar sets können auch von Unicode-Strings oder anderen widechar sets erstellt werden) enthält einen optionalen Encoding-Parameter, der die CodePage für die übergeben sets enthält. Dieses Encoding Objekt wird zur Konvertierung der ANSI Zeichen oberhalb von #127 des Eingabe-set zu Unicode-Zeichen verwendet (UTF-16), damit diese im widechar set genutzt werden können.

Widechar sets (und die Widechar Factory) unterstützt alle set Operationen. In der HTML Hilfedatei des Archivs sind die Mitglieder des IWidecharSet (stellvertretend für ein widechar set) und IWidecharSets (das Factory-Interface welches von WidecharSets Funktionen zurückgeliefert wird) beschrieben.

Der Quellcode der Units in diesem Archiv enthält keinerlei Nutzungseinschränken, nutzt es so wie Ihr wollt (ausgenommen des Verkaufs!), aber es gibt keinerlei direkte oder indirekte Garantien bzw. Gewährleistung. Ich habe einen Satz von Unittests für den Code (im Archiv enthalten) und ich bin ziemlich sicher, daß der Code so funktioniert wie er ist. Der Code nutzt die JEDI.INC Datei von der JEDI Code Bibliothek (JCL, see http://delphi-jedi.org) für Kompilerdirektiven. Wenn Ihr die Units aus diesem Archiv mit Delphi Versionen neuer als 2009 verwendet, stellt sicher das Ihr eine neue Version dieser Datei nutzt. Anderenfalls könnte der Code die Kompilerversion möglicherweise nicht korrekt feststellen. Die JCL hat ihre eigene Distributionslizenz, bitte lest den Kommentar am Anfang der JEDI.INC.

Have fun!
Peter Below

--
Peter Below (TeamB)


(Übersetzt von Assertor)
Thomas
  Mit Zitat antworten Zitat