了解 Rad Studio 中的 UTF8Encode 和 UTF8ToString
Understanding UTF8Encode and UTF8ToString in Rad Studio
由于遗留原因,我需要在 Rad Studio 中使用使用 AnsiString 而不是 UnicodeString 的旧源。
所以,我的计划是大部分时间使用String,当我需要使用这个库时,转换成AnsiString,同样,尽快从AnsiString转换成String。
String temp = L"汉语/漢語";
AnsiString raw=UTF8Encode(temp);
String dest = UTF8ToString(raw);
当我检查时,我得到 ???而不是汉语/汉语。我做错了什么?
目前,我找到了解决方案:
AnsiString UTF8ToBin(UTF8String value)
{
AnsiString dest;
dest.SetLength(value.Length());
memcpy(dest.c_str(), value.c_str(), value.Length());
return dest;
}
它允许我使用使用 AnsiString 类型的库来存储二进制数据,在本例中为 UTF8。
我很清楚我需要对二进制数据使用 TBytes,但我无法重写库。
您需要避免在 Delphi/C++Builder 2009 及更高版本中使用 AnsiString
作为二进制缓冲区。它是一个代码页字符串,随着字符串的传递,可能会导致 subtle/unexpected 从一个代码页到另一个代码页的数据转换。在您的情况下,???
是数据实际转换为不支持您尝试使用的 Unicode 字符的 Ansi 代码页的直接结果。
您确实应该对二进制数据使用 TBytes
。对于 UTF-8 编码的字符串,请使用 UTF8String
代替:
String temp = L"汉语/漢語";
UTF8String raw = UTF8String(temp);
...
String dest = String(raw);
话虽如此,由于您必须与需要 UTF-8 编码 AnsiString
作为二进制缓冲区的第 3 方库互操作 1,那么您可以至少使用 UTF8String
变量并在将它传递给库时将其类型转换(而不是分配)到 AnsiString
:
library_function(*(reinterpret_cast<AnsiString*>(&raw));
或者:
library_function(reinterpret_cast<AnsiString&>(raw));
这是有效的,因为 AnsiString
、UTF8String
和 RawByteString
都基于相同的 AnsiStringT
基本类型:
typedef AnsiStringT<0> AnsiString;
typedef AnsiStringT<65001> UTF8String;
typedef AnsiStringT<65535> RawByteString;
因此在后台共享一个共同的内存布局和实现,Delphi 会很好地接受这一点。
如果你真的想冒险,你应该更新库以使用 RawByteString
或 UTF8String
(如果不是 TBytes
)而不是 AnsiString
,那么你根本不需要类型转换2:
library_function(raw);
1:您确实需要获取该库的新版本,或者使用不同的库。
2:这就是RawByteString
原本打算针对的那种情况。它从未打算用于独立变量,而是用于可以接受任何类型的 8 位字符串作为输入而无需执行数据转换的函数参数。
由于遗留原因,我需要在 Rad Studio 中使用使用 AnsiString 而不是 UnicodeString 的旧源。
所以,我的计划是大部分时间使用String,当我需要使用这个库时,转换成AnsiString,同样,尽快从AnsiString转换成String。
String temp = L"汉语/漢語";
AnsiString raw=UTF8Encode(temp);
String dest = UTF8ToString(raw);
当我检查时,我得到 ???而不是汉语/汉语。我做错了什么?
目前,我找到了解决方案:
AnsiString UTF8ToBin(UTF8String value)
{
AnsiString dest;
dest.SetLength(value.Length());
memcpy(dest.c_str(), value.c_str(), value.Length());
return dest;
}
它允许我使用使用 AnsiString 类型的库来存储二进制数据,在本例中为 UTF8。
我很清楚我需要对二进制数据使用 TBytes,但我无法重写库。
您需要避免在 Delphi/C++Builder 2009 及更高版本中使用 AnsiString
作为二进制缓冲区。它是一个代码页字符串,随着字符串的传递,可能会导致 subtle/unexpected 从一个代码页到另一个代码页的数据转换。在您的情况下,???
是数据实际转换为不支持您尝试使用的 Unicode 字符的 Ansi 代码页的直接结果。
您确实应该对二进制数据使用 TBytes
。对于 UTF-8 编码的字符串,请使用 UTF8String
代替:
String temp = L"汉语/漢語";
UTF8String raw = UTF8String(temp);
...
String dest = String(raw);
话虽如此,由于您必须与需要 UTF-8 编码 AnsiString
作为二进制缓冲区的第 3 方库互操作 1,那么您可以至少使用 UTF8String
变量并在将它传递给库时将其类型转换(而不是分配)到 AnsiString
:
library_function(*(reinterpret_cast<AnsiString*>(&raw));
或者:
library_function(reinterpret_cast<AnsiString&>(raw));
这是有效的,因为 AnsiString
、UTF8String
和 RawByteString
都基于相同的 AnsiStringT
基本类型:
typedef AnsiStringT<0> AnsiString;
typedef AnsiStringT<65001> UTF8String;
typedef AnsiStringT<65535> RawByteString;
因此在后台共享一个共同的内存布局和实现,Delphi 会很好地接受这一点。
如果你真的想冒险,你应该更新库以使用 RawByteString
或 UTF8String
(如果不是 TBytes
)而不是 AnsiString
,那么你根本不需要类型转换2:
library_function(raw);
1:您确实需要获取该库的新版本,或者使用不同的库。
2:这就是RawByteString
原本打算针对的那种情况。它从未打算用于独立变量,而是用于可以接受任何类型的 8 位字符串作为输入而无需执行数据转换的函数参数。