我如何"解码"一个UTF-8字符?

时间:2014-08-25 00:27:07

标签: c unicode utf-8

假设我想编写一个函数来比较两个Unicode字符。我该怎么办?我阅读了一些文章(如this),但仍然没有。我们以为输入。它在0x08000xFFFF范围内,因此它将使用3个字节对其进行编码。我该如何解码呢?按位运算从wchar_t获取3个字节并存储到3 char s? C中的示例中的代码可能很棒。

这是我的C代码“解码”,但显然错误的值解码unicode ...

#include <stdio.h>
#include <wchar.h>

void printbin(unsigned n);
int length(wchar_t c);
void print(struct Bytes *b);

// support for UTF8 which encodes up to 4 bytes only
struct Bytes
{
    char v1;
    char v2;
    char v3;
    char v4;
};

int main(void)
{
    struct Bytes bytes = { 0 };
    wchar_t c = '€';
    int len = length(c);

    //c = 11100010 10000010 10101100
    bytes.v1 = (c >> 24) << 4; // get first byte and remove leading "1110"
    bytes.v2 = (c >> 16) << 5; // skip over first byte and get 000010 from 10000010
    bytes.v3 = (c >> 8)  << 5; // skip over first two bytes and 10101100 from 10000010
    print(&bytes);

    return 0;
}

void print(struct Bytes *b)
{
    int v1 = (int) (b->v1);
    int v2 = (int)(b->v2);
    int v3 = (int)(b->v3);
    int v4 = (int)(b->v4);

    printf("v1 = %d\n", v1);
    printf("v2 = %d\n", v2);
    printf("v3 = %d\n", v3);
    printf("v4 = %d\n", v4);
}

int length(wchar_t c)
{
    if (c >= 0 && c < 0x007F)
        return 1;
    if (c >= 0x0080 && c <= 0x07FF)
        return 2;
    if (c >= 0x0800 && c <= 0xFFFF)
        return 3;
    if (c >= 0x10000 && c <= 0x1FFFFF)
        return 4;
    if (c >= 0x200000 && c <= 0x3FFFFFF)
        return 5;
    if (c >= 0x4000000 && c <= 0x7FFFFFFF)
        return 6;

    return -1;
}

void printbin(unsigned n)
{
    if (!n)
        return;

    printbin(n >> 1);
    printf("%c", (n & 1) ? '1' : '0');
}

1 个答案:

答案 0 :(得分:1)

比较UTF-8编码的字符并不容易。最好不要试试。之一:

  1. 将它们转换为宽格式(32位整数)并对其进行算术比较。请参阅wstring_convert或您最喜欢的供应商特定功能;或

  2. 将它们转换为1个字符串,并使用比较UTF-8编码字符串的函数。在C ++中没有标准的方法可以做到这一点,但它是其他语言的首选方法,如Ruby,PHP等等。


  3. 为了说清楚,困难的是将原始位/字节/字符编码为UTF_8并进行比较。这是因为您的比较必须考虑编码,以了解是否比较8位,16位或更多位。如果你能以某种方式将原始数据位转换为以null结尾的字符串,那么使用常规字符串函数可以轻松地进行比较。该字符串的长度可能超过一个字节/八位字节,但它代表一个字符/代码点。


    Windows有点特殊情况。宽字符是短整数(16位)。从历史上看,这意味着UCS-2,但它已被重新定义为UTF-16。这意味着可以直接比较基本多语言平面(BMP)中的所有有效字符,因为它们将占用一个短的int,但其他人不能。我不知道在Windows上的BMP之外处理32位宽字符(表示为简单的int)的任何简单方法。