我的 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
于 16 位值,如 UTF-16。upush
所做的只是将一个完整的 Unicode 代码点添加到 a中,并string
根据需要重新分配内存。
u16tou
是我关注的部分。它遍历string16
,正常传递非代理值,并将代理对转换为完整的代码点。错误放置的代理将被忽略。
一对中的第一个代理将其最低 10 位向左移动 10 位,从而形成最终代码点的高 10 位。另一个代理将其最低 10 位添加到最后,然后将其附加到字符串中。
问题?
让我们试试最高的代码点,好吗?
U+10FFFD
,最后一个有效的 Unicode 代码点,被编码为0xDBFF 0xDFFD
UTF-16。让我们尝试解码。
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-8char *
以进行打印,我可以在终端中看到我得到了U+0FFFFD
,而不是U+10FFFD
结果。
在计算器
在gcalctool中手动进行所有转换会导致相同的错误答案。所以我的语法本身没有错,但算法错了。该算法对我来说似乎是正确的,但它以错误的答案结束。
我究竟做错了什么?