注意:如果你已经关注了我最近的问题,你会发现它们都是关于我在C语言中的Unicode库练习 - 作为我的第一批几个严肃的项目之一在C中,我遇到了很多问题,所以如果我对一件事提出太多问题,我很抱歉。UTF-8解码器在非ASCII字符上失败
我的部分库将UTF-8编码的char
指针解码为原始unsigned
代码点。但是,某些飞机不能正确解码。让我们来看看(相关)代码:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
// really simple stuff
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;
}
// UTF-8 conversions
string ctou(char *old) {
unsigned long i, byte = 0, cur = 0;
string new;
new.length = 0;
for (i = 0; old[i]; i++)
if (old[i] < 0x80) upush(&new, old[i]);
else if (old[i] < 0xc0)
if (!byte) {
byte = cur = 0;
continue;
} else {
cur |= (unsigned)(old[i] & 0x3f) << (6 * (--byte));
if (!byte) upush(&new, cur), cur = 0;
}
else if (old[i] < 0xc2) continue;
else if (old[i] < 0xe0) {
cur = (unsigned)(old[i] & 0x1f) << 6;
byte = 1;
}
else if (old[i] < 0xf0) {
cur = (unsigned)(old[i] & 0xf) << 12;
byte = 2;
}
else if (old[i] < 0xf5) {
cur = (unsigned)(old[i] & 0x7) << 18;
byte = 3;
}
else continue;
return new;
}
所有upush
呢,对了,是推动一个代码点到string
末,需要重新分配内存。 ctou
进行解码工作,并将byte
中仍然需要的字节数存储在一个序列中,以及cur
中的进行中的代码点。
该代码似乎对我来说都是正确的。我们尝试使用UTF-8解码U+10ffff
,即f4 8f bf bd
。这样做:
long i;
string b = ctou("\xf4\x8f\xbf\xbd");
for (i = 0; i < b.length; i++)
printf("%z ", b.data[i]);
应该打印出来:
10ffff
而是它打印出:
fffffff4 ffffff8f ffffffbf ffffffbd
这基本上是四个字节UTF-8的,与ffffff
前上涨了它。
有关我的代码中出现什么问题的任何指导?
顺便说一下,您的问题主题是误导。这个问题与高平面(非BMP)字符无关;它发生在** any **非ascii字符。它也与UTF-8无关,而与基本的C算法无关。你的UTF-8解码器也有一些缺陷,最糟糕的是你将解码无效的超长序列。 – 2010-09-24 14:21:47
我已编辑标题以改善相关性。如果你能让我知道你发现的其他一些错误,我会非常感激。 – 2010-09-24 14:24:11
您正在阻止两个字节的溢出,但不会再延长,例如。 0xE0,0x80,0xBC。您还允许超过0x10FFFF的代码点,代理代码单元(不应以UTF-8出现)以及大于等于0xC0字节的序列,然后是低位字节,然后是0x80-0xBF字节。具有不同代码的“while”循环/检查每个长度的情况可能更容易。但是真的,我会使用一些现有的库代码来解码UTF-8,而不是自己进行滚动(因为错误解码/无效序列最终会导致过滤器逃避并带来安全后果)。此外'upush'实现在病理上是低效的。 – bobince 2010-09-24 14:34:42