【问题标题】:UTF-16 decoder not working as expectedUTF-16 解码器未按预期工作
【发布时间】:2011-04-16 18:47:03
【问题描述】:

我的 Unicode 库中有一部分将 UTF-16 解码为原始 Unicode 代码点。但是,它没有按预期工作。

这是代码的相关部分(省略 UTF-8 和字符串操作):

typedef struct string {
    unsigned long length;
    unsigned *data;
} string;

string *upush(string *s, unsigned c) {
    if (!s->length) s->data = (unsigned *) malloc((s->length = 1) * sizeof(unsigned));
    else            s->data = (unsigned *) realloc(s->data, ++s->length * sizeof(unsigned));
    s->data[s->length - 1] = c;
    return s;
}

typedef struct string16 {
    unsigned long length;
    unsigned short *data;
} string16;

string u16tou(string16 old) {
    unsigned long i, cur = 0, need = 0;
    string new;
    new.length = 0;
    for (i = 0; i < old.length; i++)
        if (old.data[i] < 0xd800 || old.data[i] > 0xdfff) upush(&new, old.data[i]);
        else
            if (old.data[i] > 0xdbff && !need) {
                cur = 0; continue;
            } else if (old.data[i] < 0xdc00) {
                need = 1;
                cur = (old.data[i] & 0x3ff) << 10;
                printf("cur 1: %lx\n", cur);
            } else if (old.data[i] > 0xdbff) {
                cur |= old.data[i] & 0x3ff;
                upush(&new, cur);
                printf("cur 2: %lx\n", cur);
                cur = need = 0;
            }
    return new;
}

它是如何工作的?

string 是一个保存 32 位值的结构体,string16 用于 UTF-16 等 16 位值。 upush 所做的只是将完整的 Unicode 代码点添加到 string,并根据需要重新分配内存。

u16tou 是我关注的部分。它循环通过string16,正常传递非代理值,并将代理对转换为完整的代码点。错误放置的代理将被忽略。

一对中的第一个代理将其最低 10 位向左移动 10 位,从而形成最终代码点的高 10 位。另一个代理将其最低 10 位添加到最后,然后将其附加到字符串。

问题所在?

让我们试试最高的代码点,好吗?

U+10FFFD,最后一个有效的 Unicode 代码点,在 UTF-16 中编码为 0xDBFF 0xDFFD。让我们尝试解码。

string16 b;
b.length = 2;
b.data = (unsigned short *) malloc(2 * sizeof(unsigned short));
b.data[0] = 0xdbff;
b.data[1] = 0xdffd;
string a = u16tou(b);
puts(utoc(a));

使用utoc(未显示;我知道它正在工作(见下文))函数将其转换回UTF-8 char * 进行打印,我可以在终端中看到我收到@987654333 @,结果不是U+10FFFD

在计算器中

gcalctool 中手动进行所有转换会导致相同的错误答案。所以我的语法本身没有错,但算法错了。虽然算法对我来说似乎是正确的,但结果却是错误的答案。

我做错了什么?

【问题讨论】:

    标签: c decoding utf-16


    【解决方案1】:

    您似乎缺少0x10000 的偏移量。

    根据this WIKI page,UTF-16 代理对的构造如下:

    UTF-16 表示非 BMP 字符 (U+10000 到 U+10FFFF) 使用两个 代码单元,称为代理对。 前 1000016 从 代码点给出一个 20 位的值。 然后将其拆分为两个 10 位 每个值都表示为 最重要的代理人 一半放在第一个代理中。

    【讨论】:

      【解决方案2】:

      解码代理对时需要加上0x10000;引用rfc 2781,您缺少的步骤是第 5 步:

      1) 如果 W1 0xDFFF,则字符值 U 为值 W1 的。终止。 2) 判断 W1 是否在 0xD800 和 0xDBFF 之间。如果不是,则顺序 错误,使用 W1 无法获取有效字符。 终止。 3)如果没有W2(即序列以W1结束),或者如果W2 不在 0xDC00 和 0xDFFF 之间,序列错误。 终止。 4)构造一个20位无符号整数U',取低10位 W1 的 10 个高位和 10 个低位 W2 作为它的 10 个低位。 5) U'加上0x10000,得到字符值U。终止。

      即。一个解决方法是在您第一次阅读后添加一行:

      cur = (old.data[i] & 0x3ff) << 10;
      cur += 0x10000;
      

      【讨论】:

      • 哇,谢谢!添加了一个简单的缺失步骤,我的 UTF-16 解码器就可以工作了!
      • 没问题,很高兴听到它现在可以工作了。感谢您纠正我的错字:)
      猜你喜欢
      • 2013-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-18
      • 1970-01-01
      • 2011-05-22
      相关资源
      最近更新 更多