【问题标题】:UTF 8 encoding Algorithm vs UTF 16 AlgorithmUTF 8 编码算法与 UTF 16 算法
【发布时间】:2023-03-06 09:50:01
【问题描述】:

我正在尝试使用 C++ 将 unicode 字符的十进制值转换为它们的实际字符,并且我不想使用任何库。 StackOverflow 上的用户向我提供了以下函数,该函数将十进制表示形式转换为 UTF 8 字符。

当我在 OSX 上测试我的代码时,这解决了我所有的问题,但遗憾的是,当我在 Windows 上测试它时,输出的字符完全不正确。我现在明白 Windows 使用 UTF 16,这可以解释为什么在 Windows 上输出错误的字符。

问题是,由于我没有自己编写函数,所以我不知道它是如何工作的。我试过用谷歌搜索函数的每个不同部分,我知道它是 UTF 8 编码算法,我知道它使用按位运算,但我不知道它是如何工作的。函数如下:

void GetUnicodeChar(unsigned int code, char chars[5]) {
if (code <= 0x7F) {
    chars[0] = (code & 0x7F); chars[1] = '\0';
} else if (code <= 0x7FF) {
    // one continuation byte
    chars[1] = 0x80 | (code & 0x3F); code = (code >> 6);
    chars[0] = 0xC0 | (code & 0x1F); chars[2] = '\0';
} else if (code <= 0xFFFF) {
    // two continuation bytes
    chars[2] = 0x80 | (code & 0x3F); code = (code >> 6);
    chars[1] = 0x80 | (code & 0x3F); code = (code >> 6);
    chars[0] = 0xE0 | (code & 0xF); chars[3] = '\0';
} else if (code <= 0x10FFFF) {
    // three continuation bytes
    chars[3] = 0x80 | (code & 0x3F); code = (code >> 6);
    chars[2] = 0x80 | (code & 0x3F); code = (code >> 6);
    chars[1] = 0x80 | (code & 0x3F); code = (code >> 6);
    chars[0] = 0xF0 | (code & 0x7); chars[4] = '\0';
} else {
    // unicode replacement character
    chars[2] = 0xEF; chars[1] = 0xBF; chars[0] = 0xBD;
    chars[3] = '\0';
}
}

所以这是我的问题,有人知道将 UTF 8 编码函数转换为 UTF 16 的方法吗?我对这两种算法都做了一些研究,事实是,我也不是很了解。

另外,我看到人们使用函数MultiByteToWideChar,但我也无法让它工作。谁能为我提供一种方法或功能,使我可以在 Windows 上显示正确的 unicode 字符,而无需用户更改其控制台代码页?

【问题讨论】:

  • 为什么你想自己做这个?
  • @AndrewMedico 我正在制作一个开源的虚拟机,我不想依赖任何外部库。
  • 这至少是你第三次问同样的问题了。而且您仍然不了解基本问题:您使用的是 Windows 控制台,它对 Unicode 无论如何都不起作用!不是 UTF-8,不是 UTF-16。
  • @MarkRansom 如果 Windows 控制台无法使用 unicode,那么 Python、Ruby 等...如何在 Windows 上输出非 ascii 字符? #坚持
  • 我不会和 Ruby 对话,但是在 Python 中有两种方法。首先是使用不是控制台的东西,比如空闲。二是直接打印Unicode字符,Python会自动转换为当前代码页,通常是'cp437'——你可以用sys.stdout.encoding找到这个。

标签: c++ algorithm utf-8 utf-16 utf


【解决方案1】:

阅读维基百科上UTF-8UTF-16的描述,它们描述了编码算法。

试试这样的:

void GetUnicodeCharAsUtf8(unsigned int code, char chars[5])
{
    if (code <= 0x7F) {
        chars[0] = (code & 0x7F);
        chars[1] = '\0';
    } else if (code > 0x10FFFF) {
        // unicode replacement character
        chars[0] = 0xEF;
        chars[1] = 0xBF;
        chars[2] = 0xBD;
        chars[3] = '\0';
    } else {
        int count;
        if (code <= 0x7FF) {
            // one continuation byte
            count = 1;
        } else if (code <= 0xFFFF) {
            // two continuation bytes
            count = 2;
        } else {
            // three continuation bytes
            count = 3;
        }
        for (int i = 0; i < count; ++i) {
            chars[count-i] = 0x80 | (code & 0x3F);
            code >>= 6;
        }
        chars[0] = (0x1E << (6-count)) | (code & (0x3F >> count));
        chars[1+count] = '\0';
    }
}

void GetUnicodeCharAsUtf16(unsigned int code, unsigned short chars[2])
{
    if ( ((code >= 0x0000) && (code <= 0xD7FF)) ||
        ((code >= 0xE000) && (code <= 0xFFFF)) )
    {
        chars[0] = 0x0000;
        chars[1] = (unsigned short) code;
    }
    else if ((code >= 0xD800) && (code <= 0xDFFF))
    {
        // unicode replacement character
        chars[0] = 0x0000;
        chars[1] = 0xFFFD;
    }
    else
    {
        // surrogate pair
        code -= 0x010000;
        chars[0] = 0xD800 + (unsigned short)((code >> 10) & 0x3FF);
        chars[1] = 0xDC00 + (unsigned short)(code & 0x3FF);
    }
}

【讨论】:

  • 理论上 C++ 提供了这个作为standard libary 的一部分但是库支持还不是通用的(最后我检查了 g++ 还没有标题)。
  • 不过,仅当您使用 C++11 编译器时。
  • @RemyLebeau 感谢您的帮助,我只有 1 个问题。我提供的函数有一个“char”作为第二个参数。为什么您的函数使用“无符号短”代替?有没有办法让 unsigned short 变成一个字符,因为当我使用“cout”时,它只会向我显示内存中 short 的位置?
  • UTF-8 编码为 8 位值,char 处理(unsigned char 会更好)。 UTF-16 编码为 unsigned short 处理的 16 位值。 Hense UTF 格式的名称 - UTF-8 表示 8 位,UTF-16 表示 16 位。不过,std::cout 不支持 UTF-16,因此请改用std::wcout 甚至WriteConsoleW()
猜你喜欢
  • 2017-01-20
  • 2019-02-02
  • 2012-06-30
  • 2015-12-06
  • 2014-01-18
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多