Primož Gabrijelčič [email protected] http://thedelphigeek.com grafika: Flickr / Gamma-Ray Productions Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Urnik • Unicode – kaj in zakaj • Veliki razkol: Delphi.
Download ReportTranscript Primož Gabrijelčič [email protected] http://thedelphigeek.com grafika: Flickr / Gamma-Ray Productions Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Urnik • Unicode – kaj in zakaj • Veliki razkol: Delphi.
Primož Gabrijelčič [email protected] http://thedelphigeek.com grafika: Flickr / Gamma-Ray Productions Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Urnik • Unicode – kaj in zakaj • Veliki razkol: Delphi 2007 proti 2009 09.00 – 10.30 • Odmor • Podrobno: »Unicode« Delphi • Kako čez prepad? • Čas za vprašanja 11.00 – 12.30 Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija Evolucija • Win16: D1 2002 • Win32: D2, D3, D4, D5, D6, D7, D2005, D2006, D2007 2008 Win64, OS X, (iOS) • Win32: D2009, D2010, XE, XE2 … Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Unicode – kaj in zakaj Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah ANSI • American National Standards Institute • En znak = en bajt • »Primož« = $50 $72 $69 $6D $6F $9E • Na svetu je več kot 256 znakov! • Kodne strani • 128 ASCII + 128 Embarcadero Akademija CP 1250 - Primož vir: Microsoft Unicode v sodobnih Delphi aplikacijah CP 1251 - Primoђ Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija Kodne strani OEM 437 OEM 850 (WE) Ansi 1252 (WE) ISO 8859-1 (WE) OEM 852 (CE) Ansi 1250 (CE) ISO 8859-2 (CE) OEM 855 (Cyr) Ansi 1251 (Cyr) ISO 8859-5 (Cyr) OEM 857 (Tur) Ansi 1254 (Tur) ISO 8859-3 (Tur) … … OEM 932 (Jap) … Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Problemi • Lokalizacija/internacionalizacija • Vnos in shranjevanje geografsko razpršenih podatkov • Pisave s 100+ znaki Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Rešitev • CJK DBCS: OEM/ANSI 932, 936, 949, 950 • Unicode Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Unicode • Zapis vseh svetovnih pisav • Črke, številke, ločila, matematični znaki, šahovski simboli, mahjongg, domino, emotikoni, alkemija/astrologija … • 6.1: 100 pisav, > 110.000 znakov • Prostora za 1,114.112 znakov • Prvih 256 = ISO 8859-1 Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Problemi • Pomanjkanje »popolnih« tipografij • Arial Unicode MS, Calibri • Velika poraba prostora • 4 bajti na znak Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Ravni • Kodne točke: 0 - $10FFFF • Ravni: $00 - $10 • Vsaka raven: $0000 - $FFFF • Prva raven (raven 0): osnovna večjezična raven (BMP) • Najpomembnejših 65536 znakov • Raven 1: dodatni znaki • Raven 2: dodatni ideografski znaki • Raven 14: dodatni znaki za posebne namene • Ravni 15, 16: privatno področje (PUA) Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Zapis • BMP: U+hhhh • »A« = $41 = U+0041 • Druge ravni: U+hhhhh ali U+hhhhhh • » « = U+10080 • »𝒪« = U+1D4AA Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija Kompozicija • Sestavljena oblika • »ö« = U+00F6 • Komponentna oblika • »ö«= U+006F, U+0308 • Komponente (diakritična znamenja) lahko nizamo vir: StackOverflow Embarcadero Akademija Kodiranja • UCS-4 • UTF-32 • UCS-2 • UTF-16 • UTF-8 Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah UTF-32 • 4 bajti za znak • Little endian (LE) in big endian (BE) • UTF-32LE: $50 $00 $00 $00 $72 $00 $00 $00 $69 $00 $00 $00 $6D $00 $00 $00 $6F $00 $00 $00 $7E $01 $00 $00 [–] Ogromna poraba prostora [+] Enostavna manipulacija Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah UTF-16 • 2 ali 4 bajti za znak • BMP: 2 bajta • Drugo: 4 bajti; U+1D4AA = U+D835, U+DCAA • UTF-16LE: $50 $00 $72 $00 $69 $00 $6D $00 $6F $00 $7E $01 • UTF-16BE: $00 $50 $00 $72 $00 $69 $00 $6D $00 $6F $01 $7E [–] Otežkočeno delo z znaki, ki niso v BMP [+] Dober kompromis Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah UTF-8 • Od 1 do 3 bajti za znak • ASCII: 1 bajt • Evropski znaki (in drugo): 2 bajta • Preostanek: 3 bajti • Ne obstajata LE in BE • UTF-8: $50 $72 $69 $6D $6F $C5 $BE [–] Otežkočena manipulacija [+] Majhna poraba prostora Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah BOM UTF-32LE UTF-32BE UTF-16LE UTF-16BE UTF-8 $FF $FE $00 $00 $00 $00 $FE $FF $FE $FF $FF $FE $EF $BB $BF Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Veliki razkol: Delphi 2007 proti 2009 Embarcadero Akademija I. Unicode v sodobnih Delphi aplikacijah Unicode okna • CreateWindowsW • Sporočila prenašajo nize Unicode UTF-16LE • D2007: TNT Unicode Controls Embarcadero Akademija II. Unicode v sodobnih Delphi aplikacijah »Wide« API • VCL in RTL kličeta »W« različice funkcij • function GetModuleFileName(hModule: HINST; lpFilename: PWideChar; nSize: DWORD): DWORD; stdcall; • function GetModuleFileNameA(hModule: HINST; lpFilename: PAnsiChar; nSize: DWORD): DWORD; stdcall; • function GetModuleFileNameW(hModule: HINST; lpFilename: PWideChar; nSize: DWORD): DWORD; stdcall; • VCL in RTL interno uporabljata Unicode • D2007: LoadLibrary Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah III. Privzeta oblika nizov • String = UnicodeString = UTF-16LE • WideString, AnsiString • D2007: String = AnsiString; WideString Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Spremembe • I. Unicode okna • II. »Wide« API • III. Unicode nizi • Privzeto obnašanje je sedaj Unicodno, za delo z osembitnimi znaki se moramo posebej potruditi! Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah IV. Unicode izvorna koda Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Podrobno: »Unicode « Delphi Embarcadero Akademija Nizi na sto načinov • String[] • var ime: string[40]; • AnsiString • RawByteString • UTF8String • UnicodeString • WideString • UCS4String Unicode v sodobnih Delphi aplikacijah Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija AnsiString • Osembitni znaki • Nov metapodatek: kodna stran -12 -10 -8 -4 0 kodna stran velikost elementa števec referenc dolžina prvi znak • var s: AnsiString; • type CyrillicString = type AnsiString(1251); • var s: CyrillicString • Samodejno pretvarjanje kodnih strani Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah RawByteString • type RawByteString = type AnsiString($FFFF); • Prirejanje brez pretvarjanja Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah UTF8String • type UTF8String = type AnsiString(65001); • Samodejna pretvorba v UTF8 in iz njega pri prirejanju Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah UnicodeString • UTF-16LE • Štetje referenc • Delphijev dodeljevalnik pomnilnika • Length('#$D835#$DCAA' {𝒪}) = 2 • ElementToCharLen('#$D835#$DCAA') = 1 • NextCharIndex, StrNextChar Embarcadero Akademija WideString • UTF-16LE • Brez štetja referenc • COM dodeljevalnik pomnilnika • Nespremenjen glede na D2007 Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah UCS4String • type UCS4String = array of UCS4Char; • Slaba podpora: ConvertFromUTF32, ConvertToUTF32 Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah TEncoding • Memo1.Lines.LoadFromFile('tekst.txt', TEncoding.Ansi) • Memo1.Lines.SaveToStream(str, TEncoding.UTF8) • class property ANSI: TEncoding • class property ASCII: TEncoding • class property BigEndianUnicode: TEncoding • class property Default: TEncoding • class property Unicode: TEncoding • class property UTF7: TEncoding • class property UTF8: TEncoding Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah TEncoding kot pretvornik var ime16be: string; ime16be:= TEncoding.BigEndianUnicode.GetString( TEncoding.Unicode.GetBytes(FIme)); Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Character • Lastnosti znakov • GetUnicodeCategory, IsLower, IsSeparator, IsWhiteSpace … • Lastnosti nizov • IsLower, IsNumber, IsLetter … • Spreminjanje • ToLower, ToUpper, ConvertToUtf32, ConvertFromUtf32 Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah CharInSet var ch: char; if ch in ['A'..'Z'] then … ⇒ if CharInSet(ch, ['A'..'Z']) then … ⇒ if IsLetter(ch) then … Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Baze • TField.AsWideString • TField.AsString ostaja nespremenjen (Ansi) • Podatki shranjeni v UTF8 - spremenljiva dolžina niza Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Kako čez prepad? trivialno težavnost prehoda ogromno dela, še misliti si ne morete, koliko Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Tuje knjižnice in komponente • Predelujte le v skrajni sili • Raje poiščite nadomestek • Turbo Power je sedaj na SourceForgu Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Opozorila prevajalnika W1050 WideChar reduced to byte char in set expressions. Consider using 'CharInSet' function in 'SysUtils' unit. W1058 Implicit string cast with potential data loss from 'string' to 'AnsiString' W1057 Implicit string cast from 'AnsiString' to 'string' W1059 Explicit string cast W1060 Explicit string cast with potential data loss W1062 Narrowing given wide/Unicode string constant lost information W1063 Widening given AnsiChar constant to WideChar lost information W1064 Widening given AnsiString constant lost information Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Problem I: SizeOf(char) = 1 var buffer: array [0..255] of char; FillChar(Buffer, Length(Buffer), 0); ⇒ var buffer: array [0..255] of char; FillChar(Buffer, Length(Buffer) * SizeOf(buffer[0]), 0); Unicode v sodobnih Delphi aplikacijah Embarcadero Akademija Problem II: Nizi kot nosilci podatkov function ReadFromStream(s: TStream): string; var len: integer; begin s.Read(len, 4); SetLength(Result, len); s.Read(Result[1], len); end; •Rezultat: »㨰崶㼠㼿㼿 « Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Rešitev II: Nizi kot nosilci podatkov function ReadFromStream(s: TStream): RawByteString; var len: integer; begin s.Read(len, 4); SetLength(Result, len); s.Read(Result[1], len); end; Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Problem III: Čarovnije s kazalci function CountSpaces(const s: string): integer; var i : integer; pc: PChar; begin Result := 0; if s <> '' then begin pc := @(s[1]); for i := 1 to Length(s) do begin if pc^ = ' ' then Inc(Result); pc := pointer(integer(pc)+1); end; end; end; Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Rešitev III: Čarovnije s kazalci function CountSpaces(const s: string): integer; var i : integer; pc: PChar; begin Result := 0; if s <> '' then begin pc := @(s[1]); for i := 1 to Length(s) do begin if IsWhiteSpace(pc^) then Inc(Result); Inc(pc); // pc := pointer(integer(pc)+1); end; end; end; Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Pogosti viri težav • Move, FillChar, NewStr, DisposeStr, AllocMem, GetMem, StrAlloc, Read, ReadBuffer, Write, WriteBuffer • PChar, PString • MultiByteToWideChar, WideCharToMultiByte • LoadFromFile, LoadFromStream, SaveToFile, SaveToStream • »array of const« - vtUnicodeString Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Uppercase : AnsiUppercase • Uppercase('aâăá') = 'Aâăá' • AnsiUppercase('aâăá') = 'AÂĂÁ' • UpperCase, LowerCase, CompareStr, CompareText, SameStr … Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Nasveti • char ⇒ AnsiChar, PChar ⇒ PAnsiChar, string ⇒ AnsiString, PString ⇒ PAnsiString • AnsiStrings • TWideStrings ?⇒ TStrings, TWideStringList ?⇒ TStringList • CreateProcessW • PAnsiChar(AnsiString(s)) Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Popolna podpora Unicoda • Kompozicija • Nadomestni pari • Desno-levi jeziki znotraj katerih se pojavljajo levo- desni deli • Delna podpora Unicoda (samo levo-desni jeziki, samo BMP) je enostavna Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Mehak prehod • Interakcijske točke naj ostanejo Ansi • Pogojno prevajanje {$IFDEF Unicode} // ta del se prevede le v Delphiju 2009 in novejših {$ELSE} // ta del se prevede le v Delphiju 2007 in starejših {$ENDIF} Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Podvojeni podprogrami • Za lastne podprograme in za VCL/RTL function FromHex(x: string):int64; {$IFDEF Unicode}overload; function FromHex(x: AnsiString):int64; overload;{$ENDIF Unicode} function FromHex (x: AnsiString): Int64; begin Result := FromHex(string(x)); end; Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Podvojeni VCL/RTL podprogrami function var F: function var F: FindFirst(const Path: TSearchRec): Integer; FindFirst(const Path: TSearchRec): Integer; string; Attr: Integer; overload; AnsiString; Attr: Integer; overload; function FindFirst(const Path: string; Attr: Integer; var F: TSearchRec): Integer; begin Result := SysUtils.FindFirst(Path, Attr, F); end; function FindFirst(const Path: AnsiString; Attr: Integer; var F: TSearchRec): Integer; begin Result := SysUtils.FindFirst(string(Path), Attr, F); end; Embarcadero Akademija Unicode v sodobnih Delphi aplikacijah Vprašanja?