【问题标题】:How to decode/encode a UTF-8 char in c++ without wchar_t如何在没有 wchar_t 的情况下在 c++ 中解码/编码 UTF-8 字符
【发布时间】:2017-04-12 22:39:41
【问题描述】:

正如标题所述,我正在尝试将 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;
    }

为什么这段代码不起作用?我简直不明白。

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

【问题讨论】:

  • 呃,wchar_t 不会神奇地转换任何东西。它甚至不是标准的——它是一个黑客。使用适当大小的字符类型,例如char16_tchar32_t 如果您将 UTF-8 解码为更宽的字符。至于您的问题,您没有说什么不起作用,也没有显示 c 是什么数据类型。您的意思是要测试in 的值(您在循环中读取)而不是c?您是否尝试过使用调试器单步执行您的代码?
  • 您能否更清楚地了解您将 UTF-8 编码/解码到/从什么?
  • 另外,既然你希望重新实现而不是使用标准函数,你最好read the Unicode Standard。 9.0.0 版只有 1036 页。享受吧!
  • 顺便说一句,C++14 允许直接在代码中使用像 0b11000000 这样的二进制文字。它还允许0b1100'0000 分隔数字。
  • 是的,很抱歉 c 在里面,长度是 sz 我已经编辑了 OP 来反映。

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


【解决方案1】:

您似乎在测试错误的值。您的循环正在读取值 in,但您正在测试一些名为 c 的值。

当您阅读额外的字符时,您也会出错。您正在使用一些值length 而不是大概sz。而且您正在将字符添加到整数(顺便说一下,不一定是 32 位),而不是移位并与按位 OR 组合。

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

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

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 而不是流输入运算符(&gt;&gt;),并将字符组合成一个以更正常的方式使用单个值。

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;
    }
}

现在,最后一部分以大端顺序连接字节。我不知道这是否正确,因为我没有阅读标准。但这比仅仅将值相加要正确得多。它还使用有保证的 32 位数据类型,与您使用的 unsigned int 不同。

【讨论】:

    猜你喜欢
    • 2022-01-13
    • 2021-08-24
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多