如何将 UnicodeString 复制到 C++Builder Android 应用程序中的 wchar_t 数组?

How can I copy a UnicodeString to a wchar_t array in a C++Builder Android app?

我正在使用 C++Builder 10.3 Rio 为 Android 开发多平台应用程序。

我有一个数据数组如下:

typedef struct recordstruct
{
    bool shop;
    bool bought;
    wchar_t description[80];
} recordtype;

recordtype MasterItems[MAXITEMS]=
{
    false,false,L"Apples",
    false,false,L"Apricots",
    false,false,L"Avocado",
...
...
};

我已将其复制到 TEdit,并希望将值返回到 MasterItems 数组。

我以前用c_str()mbstowcs()strcpy()/wcscpy()等等

请问我该怎么做?

UnicodeString 是所有平台上的 UTF-16 编码字符串。但是,wchar_t 是一种 16 位类型,仅在 Windows 上用于 UTF-16 数据。在其他平台上,wchar_t 是用于 UTF-32 数据的 32 位类型。

这在 Embarcadero 的 DocWiki 中有记录:

String Literals char16_t and wchar_t on macOS and iOS
(也包括Android)

On macOS and iOS, char16_t is not equivalent to wchar_t (as it is on Windows):

  • On Windows, wchar_t and char16_t are both double-byte characters.
  • On macOS, iOS, and Android, however, a wchar_t is a 4-byte character.

So, to declare UTF-16 constant strings, on Windows use either the L or the u prefix, whereas on macOS, iOS, and Android, use the u prefix.

Example on Windows:

UnicodeString(L"Text"), UnicodeString(u"Text")

Example on macOS, iOS, and Android:

UnicodeString(u"Text")

Using the L prefix for string literals on macOS, iOS, and Android is not, however, wrong. In this case, UTF-32 constant strings are converted to UTF-16 strings.

For portability, use the _D macro to write constant strings that are prefixed accordingly with L or u. Example:

UnicodeString(_D("Text"))

为确保在所有平台上使用 UTF-16,System::WideChar 类型是 Windows 上的 wchar_t 和其他平台上的 char16_t 的别名。 UnicodeStringWideChar 个元素的容器。

因此,如果您对数组使用 wchar_t,那么在非 Windows 平台上,您需要先在运行时将 UnicodeString 转换为 UTF-32,例如使用 RTL 的 UnicodeStringToUCS4String() 函数,然后您可以将该数据复制到您的数组中,例如:

typedef struct recordstruct
{
    bool shop;
    bool bought;
    wchar_t description[80];
} recordtype;

recordtype MasterItems[MAXITEMS]=
{
    false,false,L"Apples",
    false,false,L"Apricots",
    false,false,L"Avocado",
    ...
};

...

#if defined(WIDECHAR_IS_WCHAR) // WideChar = wchar_t = 2 bytes

StrLCopy(MasterItems[index].description, Edit1->Text.c_str(), std::size(MasterItems[index].description)-1); // -1 for null terminator

/* or:
UnicodeString s = Edit1->Text;
size_t len = std::min(s.Length(), std::size(MasterItems[index].destination)-1); // -1 for null terminator
std::copy_n(s.c_str(), len, MasterItems[index].destination);
MasterItems[index].destination[len] = L'[=10=]';
*/

#elif defined(WIDECHAR_IS_CHAR16) // WideChar = char16_t, wchar_t = 4 bytes

UCS4String s = UnicodeStringToUCS4String(Edit1->Text);
size_t len = std::min(s.Length-1, std::size(MasterItems[index].destination)-1); // UCS4String::Length includes the null terminator!
std::copy_n(&s[0], len, MasterItems[index].destination);
MasterItems[index].destination[len] = L'[=10=]';

#else

// unsupported wchar_t size!

#endif

否则,如果你想确保你的数组在所有平台上始终是 16 位 UTF-16,那么你需要在你的数组中使用 char16_tWideChar 而不是 wchar_t . u 前缀创建一个基于 char16_t 的文字,RTL 的 _D() 宏创建一个基于 WideChar 的文字(使用 Lu根据平台),例如:

typedef struct recordstruct
{
    bool shop;
    bool bought;
    char16_t description[80]; // or: System::WideChar
} recordtype;

recordtype MasterItems[MAXITEMS]=
{
    false,false,u"Apples", // or: _D("Apples")
    false,false,u"Apricots", // or: _D("Apricots")
    false,false,u"Avocado", // or: _D("Avocado")
    ...
};

...

StrLCopy(MasterItems[index].description, Edit1->Text.c_str(), std::size(MasterItems[index].description)-1); // -1 for null terminator

/* or:
UnicodeString s = Edit1->Text;
size_t len = std::min(s.Length(), std::size(MasterItems[index].description)-1); // -1 for null terminator
std::copy_n(s.c_str(), len, MasterItems[index].description);
MasterItems[index].description[len] = u'[=11=]'; // or: _D('[=11=]')
*/