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 Report

Transcript 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?