注意:如果你已經關注了我最近的問題,你會發現它們都是關於我在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