[C] ascii to utf8
ffffffb2
ffffffc3
-78
▓├
а правильным кодом символа "т" в utf8 будет:
ffffffd1
ffffff82
Просьба подсказать, в чем может быть дело, сорс ниже:
#include <windows.h>
char *ascii_to_utf8(unsigned char c)
{
char *out;
if(c < 128)
{
out = (char *)calloc(2, sizeof(char));
out[0] = c;
out[1] = '\0';
}
else
{
out = (char *)calloc(3, sizeof(char));
out[1] = (c >> 6) | 0xC0;
out[0] = (c & 0x3F) | 0x80;
out[2] = '\0';
}
return out;
}
main()
{
// слово "тест" в ascii
unsigned char raw[] = {0xf2, 0xe5, 0xf1, 0xf2, 0x00};
int i;
char *res = ascii_to_utf8(raw[0]);
for(i = 0; i <= strlen(res) - 1; i++)
printf("%x\n", res);
printf("%d\n", res[0]);
printf("%s\n", res);
}
( 0xF2 >> 6 ) | 0xC0 -> 0xC3
( 0xF2 & 0x3F ) | 0x80 -> 0xB2
А это значит, что ваш алгоритм работает неверно...
Да и вообще непонятно, откуда взялся такой алгоритм. Он и не должен работать. Например, в ASCII есть разрыв в малых русских буквах (между "п" и "р", кажется, точно не помню) - у вас это не учтено.
А вообще - на википедии есть отличные статьи с таблицами символов и для ASCII, и для Unicode. Конвертация из Unicode в UTF8 там тоже есть.
Нужно понимать, что utf-8 это всего лишь форма представления символов UNICODE.
Бессмысленно применять алгоритм кодирования utf-8 к символам, не являющимися символами unicode.
Поэтому. Берём код символа, пусть это будет 0xF2('т' в исходной однобайтовой кодировке). По таблице преобразования из нашей однобайтовой кодировки в unicode находим код соответствующий 0xF2 - это 0x0442. И вот уже к коду 0x0442 применяем процедуру кодирования utf-8, после чего получаем
А вы ручками пробовали свой алгоритм прогнать?
( 0xF2 >> 6 ) | 0xC0 -> 0xC3
( 0xF2 & 0x3F ) | 0x80 -> 0xB2
А это значит, что ваш алгоритм работает неверно...
код был найден на просторах интернета, англоязычный автор уверял, что он отлично конвертирует ascii в utf8, как выяснилось это не так, о чем я кстати и написал, и, как видно из первого поста, прогонять пробовал.
А это значит, что ваш алгоритм работает неверно...
Да и вообще непонятно, откуда взялся такой алгоритм. Он и не должен работать. Например, в ASCII есть разрыв в малых русских буквах (между "п" и "р", кажется, точно не помню) - у вас это не учтено.
я смотрел таблицу ascii cp1251, никакого разрыва между "п" и "р" там нет, вы можете убедиться в этом сами, если пройдете по ссылке: http://www.ascii.ca/cp1251.htm
А вообще - на википедии есть отличные статьи с таблицами символов и для ASCII, и для Unicode. Конвертация из Unicode в UTF8 там тоже есть.
если вы снова прочитаете название топика, то поймете, что мне нужна вовсе не ковертация из unicode в utf8.
статью на вики http://ru.wikipedia.org/wiki/ASCII я читал, возможно, я не там смотрел, но алгоритма перевода в utf8 я там не заметил.
Да вы чего, ребята? Какие русские буквы в ASCII? Это же американский стандартный код обмена информацией.
"Впоследствии оказалось удобнее использовать 8-битные кодировки (кодовые страницы), где нижнюю половину кодовой таблицы (0—127) занимают символы US-ASCII, а верхнюю (128—255) — дополнительные символы, включая набор национальных символов. В Юникоде первые 128 символов тоже совпадают с соответствующими символами US-ASCII."
Нужно понимать, что utf-8 это всего лишь форма представления символов UNICODE.
прекрасно понимаю
Поэтому. Берём код символа, пусть это будет 0xF2('т' в исходной однобайтовой кодировке). По таблице преобразования из нашей однобайтовой кодировки в unicode находим код соответствующий 0xF2 - это 0x0442. И вот уже к коду 0x0442 применяем процедуру кодирования utf-8, после чего получаем
огромная просьба, опишите как вы сделали это программно
Тут смотрим какому номеру в аски соответствуют какие представления utf-8
+ где-то ищем таблицу аски, где номерам аски ставят в соответствие русские буквы (это можно за минуту и самому набросать программку)
Комбинируем.
profit
У нас всегда было так: кодировка DOS (866) - это ASCII, кодировка Windows (1251) - это ANSI.
Вот и не надо путать 8-ми битные национальные кодировки и ASCII. Ну нету в ASCII русской буквы 'т', зато она есть в CP1251, CP866 и KOI8-R. И коды у неё везде разные, а Вы всё в одну кучу - ascii!
int unicode2utf8 (unsigned ucs, char *buf, int nbuf)
{
if (ucs<=0x7f) {
if (nbuf>=1)
*buf=ucs;
return 1;
} else if (ucs<=0x7ff) {
if (nbuf>=2) {
*buf++ = 0xc0 | ((ucs>>6) & 0x1f);
*buf = 0x80 | (ucs & 0x3f);
}
return 2;
} else if (ucs<=0xffff) {
if (nbuf>=3) {
*buf++=0xe0 | ((ucs>>12) & 0xf);
*buf++=0x80 | ((ucs>>6) & 0x3f);
*buf=0x80 | (ucs & 0x3f);
}
return 3;
} else if (ucs<=0x1fffff) {
if (nbuf>=4) {
*buf++=0xf0 | ((ucs>>18) & 0x7);
*buf++=0x80 | ((ucs>>12) & 0x3f);
*buf++=0x80 | ((ucs>>6) & 0x3f);
*buf++=0x80 | (ucs & 0x3f);
}
return 4;
}
return -1;
}
int main (int argc, char **argv)
{
char buf[10];
int n, i;
n=unicode2utf8 (0x0442u, buf, sizeof buf);
for (i=0; i<n; i++)
printf ("%s%#02x", (i? " ": ""), (unsigned char)buf);
printf ("\n");
}
Результат выполнения.
0xd1 0x82
typedef unsigned char u8;
u8 ascii_table[] = { 0x0, 0x1 ... };
u8 utf8_table[] = { 0x0, 0x1 ... };
Я сейчас не могу выложить точные значения элементов этих кодировочных таблиц - уже нету!
При этом перевод строки производится так:
[FONT="Courier New"]char *ascii_to_utf8( char const *ascii_str )
{
u8 *result = (u8*) std::strdup( ascii_str );
while( *result ) *result = utf8_table[*result];
return result;
};[/FONT]
и так:
[FONT="Courier New"]char *utf8_to_ascii( char const *utf8_str )
{
u8 *result = (u8*) std::strdup( utf8_str );
while( *result ) *result = ascii_table[*result];
return result;
};[/FONT]
По-моему самый быстрый метод!
Итого, нашел отличную функцию преобразования ascii to utf8 (кириллица):
{
static const short utf[256] =
{
0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,
0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,
0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,
0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,
0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x402,0x403,0x201a,0x453,0x201e,
0x2026,0x2020,0x2021,0x20ac,0x2030,0x409,0x2039,0x40a,0x40c,0x40b,0x40f,0x452,
0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,0,0x2122,0x459,0x203a,0x45a,
0x45c,0x45b,0x45f,0xa0,0x40e,0x45e,0x408,0xa4,0x490,0xa6,0xa7,0x401,0xa9,0x404,
0xab,0xac,0xad,0xae,0x407,0xb0,0xb1,0x406,0x456,0x491,0xb5,0xb6,0xb7,0x451,
0x2116,0x454,0xbb,0x458,0x405,0x455,0x457,0x410,0x411,0x412,0x413,0x414,0x415,
0x416,0x417,0x418,0x419,0x41a,0x41b,0x41c,0x41d,0x41e,0x41f,0x420,0x421,0x422,
0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42a,0x42b,0x42c,0x42d,0x42e,0x42f,
0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43a,0x43b,0x43c,
0x43d,0x43e,0x43f,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,
0x44a,0x44b,0x44c,0x44d,0x44e,0x44f
};
int cnt = strlen(in),
i = 0, j = 0;
for(; i < cnt; ++i)
{
long c = utf[(unsigned char)in];
if (c < 0x80) out[j++] = c;
else if (c < 0x800)
{
out[j++] = c >> 6 | 0xc0;
out[j++] = c & 0x3f | 0x80;
}
else if (c < 0x10000)
{
out[j++] = c >> 12 | 0xe0;
out[j++] = c >> 6 & 0x3f | 0x80;
out[j++] = c & 0x3f | 0x80;
}
else if (c < 0x200000)
{
out[j++] = c >> 18 | 0xf0;
out[j++] = c >> 12 & 0x3f | 0x80;
out[j++] = c >> 6 & 0x3f | 0x80;
out[j++] = c & 0x3f | 0x80;
}
}
out[j] = '\0';
}