經(jīng)過黃叉叉的唆使,我也在家里裝上了Delphi2010,,一般情況下編譯問題不大,,但是好多從以前的工程轉(zhuǎn)過來的項目上就有些問題了,經(jīng)常性的問題就是Unicode的問題,!于是網(wǎng)絡Google一番,,在Delphi的官方站點上發(fā)現(xiàn)了Unicode的一些說明,于是大致的翻譯記錄一下,,原文地址:http://docwiki./RADStudio/en/Unicode_in_RAD_Studio 在RADStudio中,,基于ANSI-字符串改為基于Unicode字符串:現(xiàn)在的默認情況下,string類型是一個Unicode字符串(UnicodeString),。這個主題將會告訴你如何更好的去處理字符串,。 RADStudio現(xiàn)在完全支持Unicode標準,但是在您的某些涉及到字符串操作部分的代碼將會需要一些變動,,雖然已經(jīng)花了很多功夫以使用戶進行最低限度的變化,!這是新的數(shù)據(jù)類型的介紹,,現(xiàn)有的數(shù)據(jù)類型和功能仍和以往一樣。根據(jù)公司內(nèi)部的Unicode轉(zhuǎn)換的經(jīng)驗,,現(xiàn)有的開發(fā)應用程序應該比較順利遷移,。 現(xiàn)有的String類型 預先存在的數(shù)據(jù)類型AnsiString和WideString功能與以前一樣的方式。 注意:ShortString最多包含255個字符,,字符為單字節(jié)數(shù)據(jù),,且只有一個字符計數(shù),不包含編碼頁(codepage)信息,。對于特定應用,,ShortString可以包含UTF-8數(shù)據(jù),但缺乏普遍性,。 此前系統(tǒng)的string實質(zhì)上是代表AnsiString.下表是之前AnsiString各字段含義的內(nèi)存表示格式:
在RADStudio中,AnsiString格式已經(jīng)發(fā)生改變,,新加入了兩個字段(fields),分別是“編碼頁”字段和“元素大小”字段(CodePageandElemSize),。從而使得AnsiString表示格式與新的UnicodeString類型完全兼容,。 WideString WideString之前用于Unicode字符數(shù)據(jù)。其格式本質(zhì)上與WindowsBSTR完全一樣,。WideString仍舊適用于COM應用,。 新String類型:UnicodeString 在RADStudio中,新的默認string類型是UnicodeString類型,。 在Delphi中,,Char和Pchar類型分別為WideChar和PwideChar。 注意:2009之前的版本,,string代表AnsiString,,而Char和Pchar類型分別為AnsiChar和PansiChar,此一區(qū)別,,需要特別注意,。 在C++中,_TCHAR映射到一個可選的浮動興致的定義_TCHAR可以作為wchart_t也可以是Char VCL中限制使用的是UnicodeString類型,,它不再是單字節(jié)或MBCS字符串的字符串值。 現(xiàn)在的UnicodeString的內(nèi)存存儲格式為:
CodePage:Word; ElemSize:Word; refCount:Integer; Len:Integer; caseIntegerof 1:array[0..0]ofAnsiChar; 2:array[0..0]ofWideChar; end; UnicodeString加入了“編碼頁”和“元素大小”二字段來說明string內(nèi)容,。UnicodeString與所有其它string類型賦值兼容(isassignmentcompatiblewithallotherstringtypes),。但是,在AnsiString和UnicodeString之間的賦值仍然會出現(xiàn)“往上轉(zhuǎn)換”或“朝下轉(zhuǎn)換”(stilldotheappropriateupordownconversions),。應注意,,不建議將UnicodeString類型賦值給AnsiString類型,這可能導致數(shù)據(jù)丟失,。 還應注意AnsiString也包含了CodePage和ElemSize二字段,。 UnicodeString在UTF-16里邊,,有如下理由: UTF-16與底層操作系統(tǒng)格式匹配。 UTF-16減少了顯式/隱式的轉(zhuǎn)換,。 調(diào)用WindowsAPI時的性能更高,。 操作系統(tǒng)不需與UTF-16作任何轉(zhuǎn)換。 基本多語言平臺(BMP)已包含了目前世界上絕大多數(shù)流行語言文字字形,,且適合于單個UTF-16字符(16bits),。 Unicode“替換對”(surrogatepairs)與多字節(jié)字符集(MBCS)類似,且更可預測,,也更標準,。 調(diào)度COM接口時,UnicodeString能夠提供與WideString之間的雙向轉(zhuǎn)換,。 UTF-16中的字符可以是2或4字節(jié),,因此,string中元素的數(shù)目不必一定等于其字符數(shù)目,。如果string中只包含BMP字符,,則字串中的字符個數(shù)和元素個數(shù)一定相等。 采用UnicodeString有如下好處:
WideString沒有引用計數(shù),因此UnicodeString在某些類型的應用中更加靈活、更加高效(WideString更合適COM),。 索引 UnicodeString類型的實例可以尋址字符,。尋址以1為基,如同AnsiString一樣,。參考下述代碼: varC:Char; S:string; begin ... C:=S[1]; ... end; 此種情況下,,編譯器必須確保S中的數(shù)據(jù)具有適當?shù)母袷健>幾g器產(chǎn)生代碼必須確保對字串元素的賦值具有合適的類型,,并通過調(diào)用UniqueString函數(shù),,保證實例的唯一性(即,以“1”為基的引用),。代碼中,,由于字串可能包含Unicode數(shù)據(jù),編譯器在尋址字符陣列之前還需調(diào)用UniqueString函數(shù),。 編譯器條件 在Delphi及C++Builder中,,可以使用條件編譯允許Unicode和非Unicode代碼兼容共存。 Delphi {$IFDEFUNICODE} C++Builder #ifdef_DELPHI_STRING_UNICODE 變化摘要
下述操作與字符大小無關(guān):
+ + Concat(,)
CompareStr() CompareText()等
代碼//GetModuleFileName例子: functionModuleFileName(Handle:HMODULE):string; varBuffer:array[0..MAX_PATH]ofChar; begin SetString(Result,Buffer, GetModuleFileName(Handle,Buffer,Length(Buffer))); end; //GetWindowText例子: functionWindowCaption(Handle:HWND):string; begin SetLength(Result,1024); SetLength(Result, GetWindowText(Handle,PChar(Result),Length(Result))); end; //String字符索引舉例: functionStripHotKeys(constS:string):string; varI,J:Integer; LastChar:Char; begin SetLength(Result,Length(S)); J:=0; LastChar:=#0; forI:=1toLength(S)do begin if(S[I]'&')or(LastChar='&')then begin Inc(J); Result[J]:=S[I]; end; LastChar:=S[I]; end; SetLength(Result,J); end; 與“字符大小”相關(guān)的代碼結(jié)構(gòu) 在些操作確實與字符大小相關(guān),。下面函數(shù)及特征列表中也包含了可能的“可移植”版本??梢来酥貙懽约旱拇a,,以便于移植,也就是使得你的代碼在AnsiString和UnicodeString變量中都能夠正常運行,。 SizeOf()–改用可移植指令Length(). Move(...CharCount)–改用可移植的Move(...CharCount*SizeOf(Char)). StreamRead/Write--改用可移植的AnsiString,SizeOf(Char)或Tencoding類,。 FillChar(,,)--改用*SizeOf(Char)(填充#0時),或用StringOfChar函數(shù),。 GetProcAddress(,)–改用提供的重載函數(shù)并改為PWideChar. 使用類型轉(zhuǎn)換或Pchar作指針運算—在文件頂端加入{IFDEFPByte=PChar}(用Pchar作指針運算時時),。或用{POINTERMATH}編譯指令,,對所有的類型指針打開(即設為ON),,以便按照“元素大小”來增/減量(increment/decrement)。 字符集合結(jié)構(gòu) 可能需要修改的結(jié)構(gòu):
特別注意下列有問題的代碼結(jié)構(gòu) 類型轉(zhuǎn)換將類型模糊化: 有疑問的類型轉(zhuǎn)換–產(chǎn)生警告: 直接構(gòu)造、操作或訪問字串內(nèi)部結(jié)構(gòu),。有些,比如AnsiString,,其內(nèi)部已經(jīng)變化,,因此是不安全的,。建議使用StringRefCount,StringCodePage,StringElementSize及其它函數(shù)來獲取字串信息。 運行時庫 重載.對函數(shù)PChar,,已有對應版本PAnsiChar和PWideChar,,建議使用適當函數(shù)。 SysUtils.AnsiXXXX函數(shù),,如AnsiCompareString: AnsiStringsunit中的AnsiXXXX函數(shù)提供了SysUtils.AnsiXXXX函數(shù)相同的功能,,但其只適用于AnsiString.AnsiStrings.AnsiXXXX對AnsiString能夠給出比SysUtils.AnsiXXXX函數(shù)更好的性能,其原因是它們不進行隱含轉(zhuǎn)換操作,。而后者同時適用于AnsiString和UnicodeString,。 Write/Writeln和Read/Readln 繼續(xù)轉(zhuǎn)換到/從ANSI/OEM代碼頁。 控制臺是主要的ANSIorOEM 為以前的應用程序提供更好的兼容性,。 TFDD(文本文件設備驅(qū)動程序): TTextRec和TFileRec. 文件名是WideChar,但是同上所說,數(shù)據(jù)是ANSI/OEM. PByte–用$POINTERMATHON聲明,。允許陣列尋址及指針運算,如同PAnsiChar. 字串信息函數(shù)Stringinformationfunctions: StringElementSize返回實際數(shù)據(jù)的大小,。 StringCodePage返回的字符串數(shù)據(jù)的代碼頁,。 StringRefCount返回的引用計數(shù)。 RTL提供了幫助函數(shù),,可幫助在“編碼頁”和“元素大小”之間進行顯式的轉(zhuǎn)換,。通常開發(fā)人員在字符陣列上使用MOVE函數(shù)時,并不知道元素大小,。但若能確認所有的RValue引用都產(chǎn)生了對RTL的正確調(diào)用從而保證了合適的元素大小,,問題就得以緩解。 組件和類
Encodingcanbeoverridden. 考慮使用TStringBuilder替代TStringStream去從bitsandpieces來構(gòu)造一個字符串
支持UTF-8. 支持UTF-16,UTF-16be,UTF-16le ByteOrderMark(BOM)support. Youcancreatedescendentclassesforuser-specificencodings.(您可以繼承該類創(chuàng)建自己的特定編碼)
StreamasUTF-8onlyifcomponenttype,propertyornamecontainsnon-ASCII-7characters. Stringpropertyvaluesarestillstreamedin“#”escapedformat. MayallowvaluesasUTF-8aswell(openissue). OnlychangeinbinaryformatispotentialforUTF-8dataforcomponentname,properties,andtypename. 字節(jié)順序標志(ByteOrderMark) 就在文件中加入“字節(jié)順序標志”(BOM)以表示其編碼:
StepstoUnicode-enableyourapplications 用戶需要進行如下步驟:
新增Delphi編譯警告 NewwarningshavebeenaddedtotheDelphi編譯程序新增了類型轉(zhuǎn)換(如由UnicodeString或WideString朝下轉(zhuǎn)換成AnsiString或AnsiChar)相關(guān)的可能錯誤警告,。當將應用轉(zhuǎn)換到Unicode時,,應該使能警告1057和1058,以支持在代碼中發(fā)現(xiàn)問題區(qū)域,。
建議 保存源文件中的UTF-8格式: Delphi2005,2006,2007都支持. 文件仍然能夠以Ansi的形式編譯(可以使用codepage編譯器開關(guān)). WriteaUTF-8BOMtosourcefile.Makesureyoursourcecontrolmanagementsystemsupportsthesefiles(mostdo). PerformIDErefactoringwhencodemustbeAnsiStringorAnsiChar(codeisstillportable). 靜態(tài)代碼審查:
|
|