0

例如,我有 AnsiChar “A”,我想将其转换为宽字符(不进行类型转换!)。我正在考虑一些内存操作,但我不知道 AnsiChar 在 WideChar 中(在内存中)的样子。也许还有一个 WinAPI 命令?

4

2 回答 2

13

类型转换有什么问题?

如果你这样做,它会起作用,但我会在这篇文章的后面告诉你为什么它是错误的。:p

var
  A: AnsiChar;
  B: WideChar;
begin
  A := 'a';
  B := WideChar(A);

关于 ANSI 和 ASCII(以及 UCS-2)

AnsiChars 是单字节字符。WideChars 是采用 UCS-2 编码的双字节字符,它是 UTF-16 的子集。

这意味着对于前 127 个 ANSI 字符(这是 ASCII 字符集,包含用普通英语知道的大多数字符)几乎相同,除了它是 2 个字节而不是 1 个字节。因此,在 ASCII 中具有 40 美元(十六进制)字节值的大写字母“A”变成了字节 $00 + $40 作为 WideChar。它们只是零填充。

对于 ANSI 集的上半部分,这并不容易,因为这些字符可能具有不同的含义,具体取决于所使用的代码页。此范围可以包含希腊字符、西欧字符(如 é)或其他字符,但不能包含所有字符,因为该范围内只能容纳 128 个字符。因此,要将 ANSI 转换为 WideChar,您必须知道(或假设)代码页。所有(或大部分)代码页在widechar 支持的65536 个不同字符的总范围内都有不同的位置。

关于类型转换

也就是说,我可以在上面的代码片段中添加一个 é,它仍然可以正常工作,但不小心。Delphi 实际上只是将字节值转换为双字节值,因此将 AnsiChar 类型转换为 WideChar 基本上与将 Byte 分配给 Word 相同。没有进行真正的转换。碰巧的是,不仅 UTF-16 的第一个“Basic Latin”平面与 ASCII 匹配,而且第二个“Latin1 补充平面”与西欧人在其 ANSI 表中的 ISO 8859-1 字符集匹配。因此,我只需0在现有字符之间添加带有值的字节,就可以将所有文本迁移到 WideCharacters。

但并不是所有人都这么幸运。如果您在 Ansi 中有俄语文本,则此类型转换将不起作用。要正确执行此操作,请确保您拥有 Delphi 2009 或更高版本,它支持 unicode 字符串并具有各种工具来在编码之间和各种 ANSI 代码页之间进行转换。

顺便说一句,对于 AnsiChar 到 WideChar 你需要一个类型转换,这毕竟是一个普通的整数赋值,但你实际上可以将一个 AnsiString 分配给一个 WideString 并且 Delphi 将为你隐藏所有转换,并实际将其编译为调用to _WStrFromLStr,它在System单元中定义,以防您想研究它是如何工作的。

我希望这能回答您的具体问题,但是,您仍然可能想阅读每个软件开发人员绝对、肯定必须了解 Unicode 和字符集的绝对最低要求(没有借口!)。一般来说,这是对 unicode 的一个很好的解释。在其中,您会发现我提到的 Ansi、ASCII 和 UCS-2,但它们都放在更多的上下文中。

于 2013-06-29T23:00:35.867 回答
8

提供了 Windows API 函数 MultiByteToWideChar 来执行此转换。当然,您需要指定输入数据的代码页。例如:

function AnsiCharToWideChar(ac: AnsiChar; CodePage: UINT): WideChar;
begin
  if MultiByteToWideChar(CodePage, 0, @ac, 1, @Result, 1) <> 1 then
    RaiseLastOSError;
end;

请注意,ANSI 代码页中定义的所有字符都映射到基本多语言平面中的 Unicode 字符,因此由单个 UTF-16 字符表示。因此,上面代码的大小假设。

但是,您所做的假设以及此答案仍然存在,即单个字节表示 ANSI 字符集中的字符。对于许多字符集,这是一个有效的假设,例如像 1252 这样的单字节西方字符集。但也有像 932(日文)、949(韩文)等双字节字符集的字符集。您的整个方法以及上面的代码都针对这些代码页进行了分解。

于 2013-06-30T07:53:53.267 回答