2

我从内存中的结构中获取 16 位,我需要将它们转换为字符串。16 位代表一个 unicode 字符:

typedef struct my_struct {
    unsigned    unicode     : 16;
} my_struct;

我首先将这些位转换为一个无符号字符,它适用于小到足以容纳一个字符的值。但是,对于像“♪”这样的字符,它会错误地截断。这是我到目前为止所拥有的:

        char buffer[2] = { 0 };
        wchar_t wc[1] = { 0 };

        wc[0] = page->text[index].unicode;
        std::cout << wc[0] << std::endl; //PRINT LINE 1
        int ret = wcstombs(buffer, wc, sizeof(buffer));
        if(ret < 0)
            printf("SOMETHING WENT WRONG \n");
        std::string my_string(buffer);
        printf("%s \n", my_string.c_str()); //PRINT LINE 2

打印第 1 行当前打印:“9834”,打印第 2 行打印:“”(空字符串)。我试图让 my_string 包含“♪”。

4

3 回答 3

2

如果我正确完成了转换,UTF-16(16 位 Unicode)中的 0x9834 将转换为 UTF-8(8 位 Unicode)中的三个字节序列 0xE9、0xA0、0xB4。我不知道其他窄字节编码,但我怀疑任何会短于 2 个字节。您将两个字节的缓冲区传递给wcstombs,这意味着返回的字符串最多为 1 个字节。 wcstombs当目标缓冲区中没有更多空间时停止翻译(没有失败!)。您也未能L'\0'终止输入缓冲区。目前这不是问题,因为 wcstombs会在它到达那里之前停止翻译,但您通常应该添加额外的L'\0'.

那么该怎么办:

首先,也是最重要的,在调试这类事情时,请查看wcstombs. 我敢打赌0,因为空间不足。

其次,我会给自己一点余地。合法的 Unicode 在 UTF-8 中最多可以产生四个字节,所以我会为输出分配至少 5 个字节(不要忘记尾随'\0')。同样,您需要L'\0'输入尾随。所以:

char buffer[ 5 ];
wchar_t wc[] = { page->text[index].unicode, L'\0' };
int ret = wcstombs( buffer, wc, sizeof( buffer ) );
if ( ret < 1 ) {    //  And *not* 0
    std::cerr << "OOPS\n";
}
std::string str( buffer, buffer + ret );
std::cout << str << '\n';

当然,毕竟,(最终)显示设备如何使用 UTF-8(或多字节窄字符编码是什么——UTF-8 在 Unix 下几乎是通用的,但我'不确定Windows。)但是既然你说显示"\u9834"似乎工作,它应该没问题。

于 2013-07-29T19:04:41.167 回答
1

请阅读一下“字符编码”的含义,如下所示:什么是字符编码以及我为什么要打扰它

然后弄清楚你正在输入什么编码,以及你需要在输出上使用什么编码。这意味着要弄清楚您的文件格式/GUI 库/控制台期望什么。

然后使用像 libiconv 这样可靠的东西在它们之间进行转换,而不是像这样实现定义的几乎没用的 wcstombs()+wchar_t。

例如,您可能会发现您的输入是 UCS-2,您需要将其输出为 UTF-8。我的系统有 32 位 wchar_t,我不会指望它从 UCS-2 转换为 UTF-8。

于 2013-07-29T18:49:09.710 回答
1

要将 UTF-16 转换为 UTF-8,请使用codecvt_utf8<char16_t>

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main() {
    char16_t wstr16[2] = {0x266A, 0};
    auto conv = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{};
    auto u8str = std::string{conv.to_bytes(wstr16)};
    std::cout << u8str << '\n';
}
于 2013-07-29T18:53:47.257 回答