经过黄叉叉的唆使,我也在家里装上了Delphi2010,一般情况下编译问题不大,但是好多从以前的工程转过来的项目上就有些问题了,经常性的问题就是Unicode的问题!于是网络Google一番,在Delphi的官方站点上发现了Unicode的一些说明,于是大致的翻译记录一下,原文地址:http://docwiki./RADStudio/en/Unicode_in_RAD_Studio 在RADStudio中,基于ANSI-字符串改为基于Unicode字符串:现在的默认情况下,string类型是一个Unicode字符串(UnicodeString)。这个主题将会告诉你如何更好的去处理字符串。 RADStudio现在完全支持Unicode标准,但是在您的某些涉及到字符串操作部分的代码将会需要一些变动,虽然已经花了很多功夫以使用户进行最低限度的变化!这是新的数据类型的介绍,现有的数据类型和功能仍和以往一样。根据公司内部的Unicode转换的经验,现有的开发应用程序应该比较顺利迁移。 现有的String类型 预先存在的数据类型AnsiString和WideString功能与以前一样的方式。 注意:ShortString最多包含255个字符,字符为单字节数据,且只有一个字符计数,不包含编码页(codepage)信息。对于特定应用,ShortString可以包含UTF-8数据,但缺乏普遍性。 此前系统的string实质上是代表AnsiString.下表是之前AnsiString各字段含义的内存表示格式:
在RADStudio中,AnsiString格式已经发生改变,新加入了两个字段(fields),分别是“编码页”字段和“元素大小”字段(CodePageandElemSize)。从而使得AnsiString表示格式与新的UnicodeString类型完全兼容。 WideString WideString之前用于Unicode字符数据。其格式本质上与WindowsBSTR完全一样。WideString仍旧适用于COM应用。 新String类型:UnicodeString 在RADStudio中,新的默认string类型是UnicodeString类型。 在Delphi中,Char和Pchar类型分别为WideChar和PwideChar。 注意:2009之前的版本,string代表AnsiString,而Char和Pchar类型分别为AnsiChar和PansiChar,此一区别,需要特别注意。 在C++中,_TCHAR映射到一个可选的浮动兴致的定义_TCHAR可以作为wchart_t也可以是Char VCL中限制使用的是UnicodeString类型,它不再是单字节或MBCS字符串的字符串值。 现在的UnicodeString的内存存储格式为:
![]() ![]() CodePage:Word; ElemSize:Word; refCount:Integer; Len:Integer; caseIntegerof 1:array[0..0]ofAnsiChar; 2:array[0..0]ofWideChar; end; UnicodeString加入了“编码页”和“元素大小”二字段来说明string内容。UnicodeString与所有其它string类型赋值兼容(isassignmentcompatiblewithallotherstringtypes)。但是,在AnsiString和UnicodeString之间的赋值仍然会出现“往上转换”或“朝下转换”(stilldotheappropriateupordownconversions)。应注意,不建议将UnicodeString类型赋值给AnsiString类型,这可能导致数据丢失。 还应注意AnsiString也包含了CodePage和ElemSize二字段。 UnicodeString在UTF-16里边,有如下理由: UTF-16与底层操作系统格式匹配。 UTF-16减少了显式/隐式的转换。 调用WindowsAPI时的性能更高。 操作系统不需与UTF-16作任何转换。 基本多语言平台(BMP)已包含了目前世界上绝大多数流行语言文字字形,且适合于单个UTF-16字符(16bits)。 Unicode“替换对”(surrogatepairs)与多字节字符集(MBCS)类似,且更可预测,也更标准。 调度COM接口时,UnicodeString能够提供与WideString之间的双向转换。 UTF-16中的字符可以是2或4字节,因此,string中元素的数目不必一定等于其字符数目。如果string中只包含BMP字符,则字串中的字符个数和元素个数一定相等。 采用UnicodeString有如下好处:
WideString没有引用计数,因此UnicodeString在某些类型的应用中更加灵活、更加高效(WideString更合适COM)。 索引 UnicodeString类型的实例可以寻址字符。寻址以1为基,如同AnsiString一样。参考下述代码: varC:Char; S:string; begin ... C:=S[1]; ... end; 此种情况下,编译器必须确保S中的数据具有适当的格式。编译器产生代码必须确保对字串元素的赋值具有合适的类型,并通过调用UniqueString函数,保证实例的唯一性(即,以“1”为基的引用)。代码中,由于字串可能包含Unicode数据,编译器在寻址字符阵列之前还需调用UniqueString函数。 编译器条件 在Delphi及C++Builder中,可以使用条件编译允许Unicode和非Unicode代码兼容共存。 Delphi {$IFDEFUNICODE} C++Builder #ifdef_DELPHI_STRING_UNICODE 变化摘要
下述操作与字符大小无关:
+ + 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; 与“字符大小”相关的代码结构 在些操作确实与字符大小相关。下面函数及特征列表中也包含了可能的“可移植”版本。可依此重写自己的代码,以便于移植,也就是使得你的代码在AnsiString和UnicodeString变量中都能够正常运行。 SizeOf()–改用可移植指令Length(). Move(...CharCount)–改用可移植的Move(...CharCount*SizeOf(Char)). StreamRead/Write--改用可移植的AnsiString,SizeOf(Char)或Tencoding类。 FillChar(,,)--改用*SizeOf(Char)(填充#0时),或用StringOfChar函数。 GetProcAddress(,)–改用提供的重载函数并改为PWideChar. 使用类型转换或Pchar作指针运算—在文件顶端加入{IFDEFPByte=PChar}(用Pchar作指针运算时时)。或用{POINTERMATH}编译指令,对所有的类型指针打开(即设为ON),以便按照“元素大小”来增/减量(increment/decrement)。 字符集合结构 可能需要修改的结构:
特别注意下列有问题的代码结构 类型转换将类型模糊化: 有疑问的类型转换–产生警告: 直接构造、操作或访问字串内部结构。有些,比如AnsiString,其内部已经变化,因此是不安全的。建议使用StringRefCount,StringCodePage,StringElementSize及其它函数来获取字串信息。 运行时库 重载.对函数PChar,已有对应版本PAnsiChar和PWideChar,建议使用适当函数。 SysUtils.AnsiXXXX函数,如AnsiCompareString: AnsiStringsunit中的AnsiXXXX函数提供了SysUtils.AnsiXXXX函数相同的功能,但其只适用于AnsiString.AnsiStrings.AnsiXXXX对AnsiString能够给出比SysUtils.AnsiXXXX函数更好的性能,其原因是它们不进行隐含转换操作。而后者同时适用于AnsiString和UnicodeString。 Write/Writeln和Read/Readln 继续转换到/从ANSI/OEM代码页。 控制台是主要的ANSIorOEM 为以前的应用程序提供更好的兼容性。 TFDD(文本文件设备驱动程序): TTextRec和TFileRec. 文件名是WideChar,但是同上所说,数据是ANSI/OEM. PByte–用$POINTERMATHON声明。允许阵列寻址及指针运算,如同PAnsiChar. 字串信息函数Stringinformationfunctions: StringElementSize返回实际数据的大小。 StringCodePage返回的字符串数据的代码页。 StringRefCount返回的引用计数。 RTL提供了帮助函数,可帮助在“编码页”和“元素大小”之间进行显式的转换。通常开发人员在字符阵列上使用MOVE函数时,并不知道元素大小。但若能确认所有的RValue引用都产生了对RTL的正确调用从而保证了合适的元素大小,问题就得以缓解。 组件和类
Encodingcanbeoverridden. 考虑使用TStringBuilder替代TStringStream去从bitsandpieces来构造一个字符串
支持UTF-8. 支持UTF-16,UTF-16be,UTF-16le ByteOrderMark(BOM)support. Youcancreatedescendentclassesforuser-specificencodings.(您可以继承该类创建自己的特定编码)
StreamasUTF-8onlyifcomponenttype,propertyornamecontainsnon-ASCII-7characters. Stringpropertyvaluesarestillstreamedin“#”escapedformat. MayallowvaluesasUTF-8aswell(openissue). OnlychangeinbinaryformatispotentialforUTF-8dataforcomponentname,properties,andtypename. 字节顺序标志(ByteOrderMark) 就在文件中加入“字节顺序标志”(BOM)以表示其编码:
StepstoUnicode-enableyourapplications 用户需要进行如下步骤:
新增Delphi编译警告 NewwarningshavebeenaddedtotheDelphi编译程序新增了类型转换(如由UnicodeString或WideString朝下转换成AnsiString或AnsiChar)相关的可能错误警告。当将应用转换到Unicode时,应该使能警告1057和1058,以支持在代码中发现问题区域。
建议 保存源文件中的UTF-8格式: Delphi2005,2006,2007都支持. 文件仍然能够以Ansi的形式编译(可以使用codepage编译器开关). WriteaUTF-8BOMtosourcefile.Makesureyoursourcecontrolmanagementsystemsupportsthesefiles(mostdo). PerformIDErefactoringwhencodemustbeAnsiStringorAnsiChar(codeisstillportable). 静态代码审查:
|
|