String 将UTF-8字符串存储在Unicode解构中
在Delphi2007中,您可以将UTF-8字符串存储在WideString中,然后将其传递到Win32函数,例如String 将UTF-8字符串存储在Unicode解构中,string,delphi,unicode,utf-8,utf-16,String,Delphi,Unicode,Utf 8,Utf 16,在Delphi2007中,您可以将UTF-8字符串存储在WideString中,然后将其传递到Win32函数,例如 var UnicodeStr: WideString; UTF8Str: WideString; begin UnicodeStr:='some unicode text'; UTF8Str:=UTF8Encode(UnicodeStr); Windows.SomeFunction(PWideChar(UTF8Str), ...) end; Delphi 20
var
UnicodeStr: WideString;
UTF8Str: WideString;
begin
UnicodeStr:='some unicode text';
UTF8Str:=UTF8Encode(UnicodeStr);
Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;
Delphi 2007不会干扰UTF8Str的内容,即它作为UTF-8编码字符串保存在WideString中
但在Delphi2010中,我正在努力找到一种方法来做同样的事情,即将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;
哪个Windows API调用希望您传递UTF-8字符串?它是ANSI字符串或Widestring(a或W函数)。宽字符串每个字符有两个字节,UTF-8字符串有一个字节(如果超出前128个ASCII字符,则有多个字节)
宽字符串中的UTF-8根本没有意义。当确实有一个Windows函数需要一个指向UTF-8字符串的指针时,您可能需要将is转换为PAnsiChar。嗯,为什么要这样做?为什么将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和string(UnicodeString)类似,但是新的UnicodeString更快,因为它是引用计数的,而WideString不是
您的代码不正确,因为UTF-8字符串每个字符的字节数可变。“A”存储为一个字节。只是一个ASCII字节码。另一方面,“ü”将存储为两个字节。因为您使用的是PWideChar,所以函数总是希望每个字符有两个字节
还有一个区别。在旧的Delphi版本(ANSI)中,Utf8String只是一个AnsiString。在Delphi的Unicode版本中,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;
我检查了一下,结果还是一样。因为我直接在内存中移动字节,所以没有在后台进行代码页转换。我相信这可以用greater eleganece实现,但重点是我认为这是实现您想要实现的目标的途径。您最初的Delphi 2007代码使用ANSI代码页将UTF-8字符串转换为宽字符串。要在Delphi2010中执行相同的操作,您应该使用带有Convert参数false的SetCodePage
var
UnicodeStr: UnicodeString;
UTF8Str: RawByteString;
begin
UTF8Str := UTF8Encode('some unicode text');
SetCodePage(UTF8Str, 0, False);
UnicodeStr := UTF8Str;
Windows.SomeFunction(PWideChar(UnicodeStr), ...)
这是一些使用INI文件的(损坏的)遗留代码。例如,该节将作为UTF8字符串传递。我知道这是错误的,但我需要保持这样导入旧设置文件。如果我传递Unicode作为节名,那么它将不匹配。我不能使用ANSI版本,因为文件名是Unicode。我用解决方案更新了我的答案。仅供参考,原始2007代码确实会干扰UTF-8数据。2007年,
UTF8Encode()。在每个版本中,将ansisting
分配给WideString
使用操作系统默认的Ansi代码页执行Ansi->UTF16转换。最后的WideString
中不包含UTF-8数据。它包含UTF-16数据。转换没有UTF-8存在的概念,因此如果原始输入使用任何非ASCII字符,可能会损坏数据。Nice。不知道:)是的,在将tempansisting
分配给最终的WideString
时,在最后一行进行了代码页转换。在最初的D2007代码中也是如此。但另一方面,您可以通过在RawByteString
上使用SetCodePage()
来避免临时AnsiString
,然后您可以将RawByteString
分配给WideString
。