Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

[C] ascii to utf8

40K
01 февраля 2010 года
himas
31 / / 13.11.2009
Пытаюсь переконвертировать ascii в utf8, нашел функцию, которая ковертирует по-одному символу. Перед тем, как модифицировать ее под работу со строкой решил протестить, в результате чего столкнулся с проблемой конвертации. На входе массив байт (в ascii кодировке слово "тест"), функции передаю первый символ массива, получаю результат:
Цитата:

ffffffb2
ffffffc3
-78
▓├


а правильным кодом символа "т" в utf8 будет:

Цитата:

ffffffd1
ffffff82



Просьба подсказать, в чем может быть дело, сорс ниже:

Код:
#include <stdio.h>
#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);
}
24K
01 февраля 2010 года
engel65536
50 / / 17.10.2007
А вы ручками пробовали свой алгоритм прогнать?
( 0xF2 >> 6 ) | 0xC0 -> 0xC3
( 0xF2 & 0x3F ) | 0x80 -> 0xB2
А это значит, что ваш алгоритм работает неверно...
Да и вообще непонятно, откуда взялся такой алгоритм. Он и не должен работать. Например, в ASCII есть разрыв в малых русских буквах (между "п" и "р", кажется, точно не помню) - у вас это не учтено.
А вообще - на википедии есть отличные статьи с таблицами символов и для ASCII, и для Unicode. Конвертация из Unicode в UTF8 там тоже есть.
43K
01 февраля 2010 года
loki231
76 / / 27.09.2009
Да вы чего, ребята? Какие русские буквы в ASCII? Это же американский стандартный код обмена информацией.

Нужно понимать, что utf-8 это всего лишь форма представления символов UNICODE.

Бессмысленно применять алгоритм кодирования utf-8 к символам, не являющимися символами unicode.

Поэтому. Берём код символа, пусть это будет 0xF2('т' в исходной однобайтовой кодировке). По таблице преобразования из нашей однобайтовой кодировки в unicode находим код соответствующий 0xF2 - это 0x0442. И вот уже к коду 0x0442 применяем процедуру кодирования utf-8, после чего получаем
 
Код:
{ 0xd1, 0x82 }
40K
02 февраля 2010 года
himas
31 / / 13.11.2009
engel65536
Цитата:

А вы ручками пробовали свой алгоритм прогнать?
( 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 я там не заметил.

40K
02 февраля 2010 года
himas
31 / / 13.11.2009
loki231
Цитата:

Да вы чего, ребята? Какие русские буквы в ASCII? Это же американский стандартный код обмена информацией.


"Впоследствии оказалось удобнее использовать 8-битные кодировки (кодовые страницы), где нижнюю половину кодовой таблицы (0—127) занимают символы US-ASCII, а верхнюю (128—255) — дополнительные символы, включая набор национальных символов. В Юникоде первые 128 символов тоже совпадают с соответствующими символами US-ASCII."

Цитата:

Нужно понимать, что utf-8 это всего лишь форма представления символов UNICODE.


прекрасно понимаю

Цитата:

Поэтому. Берём код символа, пусть это будет 0xF2('т' в исходной однобайтовой кодировке). По таблице преобразования из нашей однобайтовой кодировки в unicode находим код соответствующий 0xF2 - это 0x0442. И вот уже к коду 0x0442 применяем процедуру кодирования utf-8, после чего получаем


огромная просьба, опишите как вы сделали это программно

36K
02 февраля 2010 года
sstorm
55 / / 25.03.2009
http://kellyjones.netfirms.com/webtools/ascii_utf8_table.shtml
Тут смотрим какому номеру в аски соответствуют какие представления utf-8

+ где-то ищем таблицу аски, где номерам аски ставят в соответствие русские буквы (это можно за минуту и самому набросать программку)

Комбинируем.


profit
24K
02 февраля 2010 года
engel65536
50 / / 17.10.2007
ASCII cp1251 - это как так?!
У нас всегда было так: кодировка DOS (866) - это ASCII, кодировка Windows (1251) - это ANSI.
43K
02 февраля 2010 года
loki231
76 / / 27.09.2009
Цитата:
"Впоследствии оказалось удобнее использовать 8-битные кодировки (кодовые страницы), где нижнюю половину кодовой таблицы (0—127) занимают символы US-ASCII, а верхнюю (128—255) — дополнительные символы, включая набор национальных символов. В Юникоде первые 128 символов тоже совпадают с соответствующими символами US-ASCII."



Вот и не надо путать 8-ми битные национальные кодировки и ASCII. Ну нету в ASCII русской буквы 'т', зато она есть в CP1251, CP866 и KOI8-R. И коды у неё везде разные, а Вы всё в одну кучу - ascii!

Код:
#include <stdio.h>

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");
}


Результат выполнения.

 
Код:
loki@debian:~/utf-8$ ./unicode2utf8
0xd1 0x82
16K
03 февраля 2010 года
asmforce
186 / / 05.01.2010
Самое лучшее, что я придумал:

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]


По-моему самый быстрый метод!
43K
03 февраля 2010 года
loki231
76 / / 27.09.2009
Если есть iconv() - то нет проблемы.
40K
06 февраля 2010 года
himas
31 / / 13.11.2009
Пробовал кодировать символы по их десятеричным кодам (по типу алгоритма http://www.unix.com/high-level-programming/10594-howto-convert-ascii-utf-8-back-c.html) - но код там не совсем верный, так как последний символ ограничен числом 249 (а должен быть 255), да и символы с кодами 127 < x < 192 вообще не отображаются (потому что первым байтом ставится 0). Увы, коды из этого диапазона очень сильно разбросаны по utf8 таблице, поэтому я пришел к выводу, что намного проще составить массив кодов, чем писать огромный алгоритм с условиями для каждого символа (как по ссылке выше).

Итого, нашел отличную функцию преобразования ascii to utf8 (кириллица):
Код:
void ascii2utf8_static(const char *in, char *out)
{
    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';
}
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог