Delphi WideString 和 Delphi 2009+。

13
我正在编写一个保存宽字符串到二进制文件的类。为此我在使用 Delphi 2005 ,但是程序将来需要移植到 Delphi 2010。我感到非常不确定,有人可以确认以下几点吗?
  1. Delphi 2005 的 WideString 类型与 Delphi 2010 的 String 类型完全相同。
  2. Delphi 2005 的 WideString 字符和 Delphi 2010 的 String 字符保证始终为2个字节。
由于存在各种 Unicode 格式,我不想出现字符串中的某些字符突然变成3个字节这种情况。
编辑:找到了这个:“我确实说的是UnicodeString, 而不是 WideString。WideString仍然存在,没有改变。WideString是由 Windows 内存管理器分配的,应用于与 COM 对象的交互。WideString 直接映射到 COM 中的 BSTR 类型。” 在 http://www.micro-isv.asia/2008/08/get-ready-for-delphi-2009-and-unicode/ 现在我更加困惑了。所以 Delphi 2010 的 WideString 不同于 Delphi 2005 的 WideString 吗?我应该使用 UnicodeString 吗?
编辑 2: Delphi 2005 中没有 UnicodeString 类型。FML。

2
在阅读了一份声明,其中提到“WideString仍然存在且未更改”,为什么您会得出Delphi 2010 WideString与Delphi 2005 WideString不同的结论呢? - Rob Kennedy
6个回答

14
针对您的第一个问题: WideString并不完全与D2010的string类型相同。 WideString是与以往相同的COM BSTR类型。它由Windows管理,没有引用计数,因此每次将它传递给其他地方时都会复制整个BSTR。
针对您的第二个问题,默认的char类型现在是WideChar,这些字符与一直使用的WideString中的字符相同。它是UTF-16编码,每个字符占用2个字节。如果将WideString数据保存到文件中,则可以轻松地将其加载到UnicodeString中。这两种类型之间的区别与内存管理有关,而不是数据格式。

但是在Delphi 2005中没有UnicodeString类型!我该怎么办?如果它与Delphi 2010字符串不同,我不想使用WideString。 - David
@David:请检查最后两个句子。字符串数据完全相同。不同之处在于UnicodeString使用更有效的内存管理模型。 - Mason Wheeler

4
正如其他人提到的那样,Delphi 2009及以上版本中的字符串(实际上是UnicodeString数据类型)与之前版本中的WideString数据类型不等同,但数据内容格式相同。它们都将字符串保存在UTF-16中。因此,如果您在以前版本的Delphi中使用WideString保存文本,则应该能够使用最近版本的Delphi(2009及以上版本)中的string数据类型正确读取它。
您应该注意,UnicodeString的性能远优于WideString。因此,如果您要在Delphi 2005和Delphi 2010中使用相同的源代码,建议您在代码中使用带有条件编译的字符串类型别名,这样您就可以同时拥有最佳效果。
type
  {$IFDEF Unicode}
  MyStringType = UnicodeString;
  {$ELSE}
  MyStringType = WideString;
  {$ENDIF}

现在你可以在源代码中使用MyStringType作为你的字符串类型。如果编译器是Unicode(Delphi 2009及以上版本),那么你的字符串类型将成为UnicodeString类型的别名,该类型是在Delphi 2009中引入的,用于保存Unicode字符串。如果编译器不是Unicode(例如Delphi 2005),那么你的字符串类型将成为旧的WideString数据类型的别名。由于它们都是UTF-16,任何版本保存的数据都应该能够被另一个正确地读取。

10
你可以这样做,而不是定义一个新的字符串名称:{$IFNDEF Unicode}type UnicodeString = WideString;{$ENDIF}。这样,你的代码就不会被非标准类型的名称所淹没。 - Rob Kennedy
是的,那将是一个更好的解决方案。谢谢。 - vcldeveloper

1
  1. Delphi 2005的WideString与Delphi 2010的String是完全相同的类型。

这并不是真的 - Delphi 2010的字符串有隐藏的内部代码页字段 - 但可能对您没有影响。

  1. Delphi 2005的WideString字符以及Delphi 2010的String字符保证始终为2个字节大小。

这是正确的。在Delphi 2010中,SizeOf(Char)= 2(Char = WideChar)。


Unicode字符串不能有不同的代码页 - 代码页字段是为了创建一个通用的二进制格式,用于Ansi字符串(需要代码页字段)和Unicode字符串(不需要代码页字段)。

如果您在Delphi 2005中将WideString数据保存到流中,并在Delphi 2010中将相同的数据加载到字符串中,则应该可以正常工作。

WideString = BSTR,在Delphi 2005和2010之间没有变化

UnicodeString = WideString,在Delphi 2005中(如果UnicodeString类型存在于Delphi 2005中-我不知道) UnicodeString = Delphi 2009及以上版本的字符串。


@Marco - Delphi 2009+中的Ansi和Unicode字符串具有共同的二进制格式(12字节头)。

UnicodeString代码页CP_UTF16 = 1200;


如果我在Delphi 2005中使用Stream.Write(AWideString[1], 2*Length(AWideString))保存一个WideString,并且它被加载到使用不同代码页的Delphi 2010应用程序中,会发生什么情况?我应该同时保存代码页和字符串吗? - David
你不能指望SizeOf(Char)=2在未来的版本中仍然有效,所以不要使用2,而是使用SizeOf(Char)。我们正在忙于将旧代码移植到2010年,有很多(SizeOf(Char)=1)的假设让我们感到疯狂。 - Toon Krijthe
我不知道Tunicodestring有一个codepage字段?我以为只有ansistring有这个字段? - Marco van de Voort

0

规则很简单:

  • 如果您只想在模块内使用 Unicode 字符串,请使用 UnicodeString 类型 (*)。
  • 如果您需要与 COM 或其他跨模块目的进行通信,请使用 WideString 类型。

您看,WideString 是一种特殊类型,因为它不是原生的 Delphi 类型。它是 BSTR 的别名/包装器 - 一种系统字符串类型,用于与 COM 或跨模块通信。作为 Unicode 只是一个副作用。

另一方面,AnsiStringUnicodeString 是原生的 Delphi 类型,在其他语言中没有类似的类型。 String 只是 AnsiStringUnicodeString 的别名。

因此,如果您需要将字符串传递给其他代码,请使用 WideString,否则请使用 AnsiStringUnicodeString 中的任何一种。简单明了。

P.S.

(*) 对于旧版 Delphi - 只需放置

{$IFNDEF Unicode}

type
  UnicodeString = WideString;

{$ENDIF}

在你的代码中的某个地方。这个修复将允许你为任何Delphi版本编写相同的代码。


0
我正在编写一个类,将宽字符串保存到二进制文件中。
当您在D2005中编写该类时,将使用Widestring。 当您迁移到D2010时,Widestring仍将有效并正常工作。 D2005中的Widestring与D2010中的WideString相同。
由于编译器可以轻松处理这些问题,因此无需考虑String = WideString在D2010中的情况。
您的输入例程以(AString: String)保存只需要一行输入即可进入过程。
procedure SaveAStringToBIN_File(AString:String);
var wkstr : Widestring;
begin
{$IFDEF Unicode}  wkstr := AString;      
{$ELSE}           wkstr := UTF8Decode(AString);   {$ENDIF}
...
   the rest is the same saving a widestring to a file stream
  write the length (word) of string then data 

end;

0

虽然D2010字符始终且确切地为2个字节,但UTF-16字符中存在与UTF-8字符相同的字符折叠和组合问题。你在窄字符串中看不到这一点,因为它们是基于代码页的,但在Unicode字符串中,可能(在某些情况下很常见)存在影响但不可见的字符。例如,在Unicode文件或流的开头的字节顺序标记(BOM),从左到右/从右到左指示符字符以及大量的组合重音。这主要影响“这个字符串在屏幕上有多少像素宽”和“这个字符串中有多少个字母”(与“这个字符串中有多少个字符”不同),但也意味着你不能随意从字符串中截取字符并假设它们是可打印的。像“从这个单词中删除最后一个字母”这样的操作变得非常复杂,并且取决于所使用的语言。

关于“我的字符串中的一个字符突然变成了3个字节长”的问题,反映了对UTF工作原理的一些困惑。在UTF-8字符串中,使用三个字节表示一个可打印字符是可能的(也是有效的),但每个字节都将是一个有效的UTF-8字符。比如,一个字母加上两个组合重音符号。在UTF-16或UTF-32中,你不会得到一个长度为3个字节的字符,但如果使用三个代码点来表示它,则可能会有6个字节(或12个字节)长。这就带我们来到了规范化(或不规范化)的问题。
但只要你把字符串作为整体处理,一切都很简单——你只需要取出字符串,将其写入文件,然后再读回来。你不必担心字符串显示和操作的细节,这些都由操作系统和库处理。在D2010中,Strings.LoadFromFile(name)和Listbox.Items.Add(string)的工作方式与D2007完全相同,对于程序员来说,Unicode相关的一切都是透明的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接