如何在没有wchar_t的情况下用c ++解码/编码UTF-8字符

时间:2017-04-12 22:39:42

标签: c++ utf-8 character-encoding

正如标题所述,我试图将UTF-8字符解码/编码为char,但我想在不使用wchar_t之类的情况下进行解码。我想自己做腿部工作。这样我知道我理解它,我显然不会或它会工作。我花了大约一个星期的时间玩弄它而我只是没有取得进展。

我尝试了几种方法,但似乎总是产生不正确的结果。我的最新尝试:

ifstream ifs(FILENAME);
    if(!ifs) {
        cerr << "Open: " << FILENAME << "\n";
        exit(1);
    }

    char in;

    while (ifs >> std::noskipws >> in) {
        int sz = 1;
        if ((in & 0xc0) == 0xc0) //0xc0 = 0b11000000
        {
                sz++;
                if((in & 0xE0) == 0xE0) //0xE0 = 0b11100000
                {
                    sz++;   
                    if((in & 0xF0) == 0xF0) //0xF0 = 0b11110000
                        sz++;   
                }
        }
        cout << sz << endl;

unsigned int a = in;
    for(int i = 1; i < sz; i++) {
        ifs >> in;
        a += in;
    }

为什么这段代码不起作用?我根本就不明白。

编辑:复制+粘贴意大利面...两个不同的var名称

1 个答案:

答案 0 :(得分:0)

您似乎正在测试错误的值。您的循环正在读取值in,但您正在针对名为c的某个值进行测试。

当你阅读其他字符时,你也错了。您使用的是某个值length,而不是大概sz。并且你将字符添加到整数(顺便说一下,不一定是32位),而不是按位移动和组合。

这些都是奇怪的错误。也许你没有在你的问题中粘贴真正的代码,或者你实际上在函数范围内有这些值。

我还建议重新安排你的分支,这有点迟钝。根据您的代码规则是:

mask     |   sz
---------+-------
0xxxxxxx | 1
10xxxxxx | 1
110xxxxx | 2
1110xxxx | 3
1111xxxx | 4

您可以定义一个简单的表格,根据高4位选择一个大小。

int sizes[16];
std::fill( sizes, sizes+16, 1 );
sizes[0xc] = 2;
sizes[0xd] = 2;
sizes[0xe] = 3;
sizes[0xf] = 4;

在循环中,让我们修复clength内容,使用大小表来避免愚蠢分支,使用istream::get代替流输入运算符({ {1}}),并以更正常的方式将字符组合成单个值。

>>

现在,最后一部分以big-endian顺序连接字节。我不知道这是否正确,因为我还没有阅读标准。但它比仅仅将价值加在一起要正确得多。它还使用保证的32位数据类型,与您使用的for( char c; ifs.get(c); ) { // Select correct character size (bytes) int sz = sizes[static_cast<unsigned char>(c) >> 4]; // Construct character char32_t val = c; while( --sz > 0 && ifs.get(c) ) { val = (val << 8) | (static_cast<char32_t>(c) & 0xff); } // Output character value in hex, unless error. if( ifs ) { std::cout << std::hex << std::fill('0') << std::setw(8) << val << std::endl; } } 不同。