9

在 Delphi 2007 中,您可以将 UTF-8 字符串存储在 WideString 中,然后将其传递给 Win32 函数,例如

var
  UnicodeStr: WideString;
  UTF8Str: WideString;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;

Delphi 2007 不会干扰 UTF8Str 的内容,即它作为 UTF-8 编码的字符串存储在 WideString 中。

但在 Delphi 2010 中,我正在努力寻找一种方法来做同样的事情,即将 UTF-8 编码的字符串存储在 WideString 中,而不会自动从 UTF-8 转换。我无法将指针传递给 UTF-8 字符串(或 RawByteString),例如以下内容显然不起作用:

var
  UnicodeStr: WideString;
  UTF8Str: UTF8String;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;
4

3 回答 3

13

您原来的 Delphi 2007 代码使用 ANSI 代码页将 UTF-8 字符串转换为宽字符串。要在 Delphi 2010 中做同样的事情,您应该使用 SetCodePage 并将 Convert 参数设置为 false。

var
  UnicodeStr: UnicodeString;
  UTF8Str: RawByteString;
begin
  UTF8Str := UTF8Encode('some unicode text');
  SetCodePage(UTF8Str, 0, False);
  UnicodeStr := UTF8Str;
  Windows.SomeFunction(PWideChar(UnicodeStr), ...)
于 2010-04-23T13:13:54.130 回答
3

嗯,你为什么要这么做?为什么要将 WideString 编码为 UTF-8 只是为了将其再次存储回 WideString。您显然使用的是 Unicode 版本的 Windows API。所以没有必要使用 UTF-8 编码的字符串。或者我错过了什么。

因为 Windows API 函数要么是 Unicode(两个字节),要么是 ANSI(一个字节)。UTF-8 在这里是错误的选择,因为它主要是每个字符包含一个字节,但对于 ASCII 基以上的字符,它使用两个或更多字节。

否则,您在 unicode Delphi 中的旧代码的等价物将是:

var
  UnicodeStr: string;
  UTF8Str: string;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;

WideString 和字符串 (UnicodeString) 类似,但新的 UnicodeString 更快,因为它是引用计数的,而 WideString 不是。

您的代码不正确,因为 UTF-8 字符串每个字符的字节数是可变的。“A”存储为一个字节。只是一个 ASCII 字节码。另一方面,“ü”将存储为两个字节。并且因为您使用的是 PWideChar,所以该函数始终需要每个字符两个字节。

还有另一个区别。在较旧的 Delphi 版本 (ANSI) 中,Utf8String 只是一个 AnsiString。在 Unicode 版本的 Delphi 中,Utf8String 是一个带有 UTF-8 代码页的字符串。所以它的行为不同。

旧代码仍然可以正常工作:

var
  UnicodeStr: WideString;
  UTF8Str: WideString;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;

它的行为与 Delphi 2007 中的行为相同。所以也许你在其他地方有问题。

米克你是对的。编译器在幕后做了一些额外的工作。因此,为了避免这种情况,您可以执行以下操作:

var
  UTF8Str: AnsiString;
  UnicodeStr: WideString;
  TempString: RawByteString;
  ResultString: WideString;
begin
  UnicodeStr := 'some unicode text';
  TempString := UTF8Encode(UnicodeStr);
  SetLength(UTF8Str, Length(TempString));
  Move(TempString[1], UTF8Str[1], Length(UTF8Str));
  ResultString := UTF8Str;
end;

我检查了,它的工作原理是一样的。因为我直接在内存中移动字节,所以没有在后台进行代码页转换。我相信它可以更优雅地完成,但重点是我认为这是你想要实现的方式。

于 2010-04-23T11:17:45.667 回答
0

哪个 Windows API 调用希望您传递 UTF-8 字符串?它可以是 ANSI 字符串或 Widestring(A 或 W 函数)。Widestrings 每个字符有两个字节,而 UTF-8 字符串有一个(如果超过前 128 个 ASCII 字符,则有更多)。

Widestring 中的 UTF-8 没有任何意义。当确实有一个 Windows 函数需要指向 UTF-8 字符串的指针时,您可能必须将 is 转换为 PAnsiChar。

于 2010-04-23T11:12:19.800 回答