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

Ваш аккаунт

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

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

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

Linux: CP1251 to UTF8

1.8K
04 сентября 2007 года
igor_nf
256 / / 13.12.2006
Решил написать консольную утилиту для перекодировки символов.
Программа получает два аргумента - имя существующего файла(CP1251) и имя создаваемого(UTF8).
Поскольку UTF8 asci-совместима, алгоритм избрал максимально лёгкий:
все символы латиницы оставляем без изменений. Если встречается кириллический символ, мы его код заменяем на соответствующий код utf8. Программа хранит таблицы кодов кириллических символов (каждая таблица - набор кодов символов от 'А' до 'я'). Обратите внимание, что кириллический код utf8 занимает два байта. Таким образом, исходный файл у нас хранит коды символов латиницы(занимают 1 байт) и кириллические коды(2 байта).

Далее код с комментариями:
Код:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

//макс. размер буфера для чтения
#define BUFSIZE 512

typedef     signed char             s8;
typedef     unsigned char           u8;
typedef     signed short            s16;
typedef     unsigned short          u16;
typedef     signed int          s32;
typedef     unsigned int            u32;
typedef     signed long long        s64;
typedef     unsigned long long      u64;

//кириллическая таблица CP1251
//
    const   u8      cp1251_cyrillic_table[] = {  

                0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xA8, 0xC6,
                0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
                0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
                0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,

                0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xB8, 0xE6,
                0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
                0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
                0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF

                };

//кириллическая таблица UTF8
//
    const   u16     utf8_cyrillic_table[] = {
               
                0xD090, 0xD091, 0xD092, 0xD093, 0xD094, 0xD095, 0xD081, 0xD096,
                0xD097, 0xD098, 0xD099, 0xD09A, 0xD09B, 0xD09C, 0xD09D, 0xD09E, 0xD09F,
                0xD0A0, 0xD0A1, 0xD0A2, 0xD0A3, 0xD0A4, 0xD0A5, 0xD0A6,
                0xD0A7, 0xD0A8, 0xD0A9, 0xD0AA, 0xD0AB, 0xD0AC, 0xD0AD, 0xD0AE, 0xD0AF,

                0xD0B0, 0xD0B1, 0xD0B2, 0xD0B3, 0xD0B4, 0xD0B5, 0xD191, 0xD0B6,
                0xD0B7, 0xD0B8, 0xD0B9, 0xD0BA, 0xD0BB, 0xD0BC, 0xD0BD, 0xD0BE, 0xD0BF,
                0xD180, 0xD181, 0xD182, 0xD183, 0xD184, 0xD185, 0xD186,
                0xD187, 0xD188, 0xD189, 0xD18A, 0xD18B, 0xD18C, 0xD18D, 0xD18E, 0xD18F,

                };

//буффер для хранения данных
    u8      utf8_buffer[BUFSIZE + BUFSIZE];

//общее число символов, предназначенных для записи в файл перед каждым очередным чтением исходного файла

    u64     total_utf8_symbols = BUFSIZE;

//
u8* is_cyrillic( u8 code ) {

    u8 i;
    u8* pos;

    if( code != 0xA8 && code != 0xB8 && (code < 0xC0 || code > 0xFF) )
        return pos = NULL;

    for( i = 0; i < sizeof( cp1251_cyrillic_table ) / sizeof( cp1251_cyrillic_table[0] ); ++i )
        if ( code == cp1251_cyrillic_table ) {
            pos = &cp1251_cyrillic_table;
        }

return pos;
}


void cp1251_to_utf8( u8* cp1251_pointer, u8* to_replace ) {

    u8 i;

//так определяем индекс cp1251-кода
    for( i = 0; *cp1251_pointer != 0xC0; --cp1251_pointer, ++i );
       
//вычленяем левый и правый байты utf8-кода, ибо буфер для записи имеет тип элементов u8

    u8  utf8_left_code = (utf8_cyrillic_table >> 8);
    u8  utf8_right_code = (utf8_cyrillic_table & 0x00ff);

    *to_replace = utf8_left_code;
    *(to_replace + 1) = utf8_right_code;

}


void replace_array( u8* array, int pos ) {

    int i;

    for( i = total_utf8_symbols - 1; i >= pos; --i )
        *(array + i + 1) = *(array + i);

}


int main( int argc, char* argv[] ) {

    u8*     CP1251 = cp1251_cyrillic_table;
    u16*    UTF8 = utf8_cyrillic_table;

//описатель исходного файла
//
    int infd;

//описатель формируемого файла
//
    int outfd;

//получаем имена файлов, пока без проверки входящих данных
//
    const char* infile = argv[1];
    char*       outfile = argv[2];

//открываем файл для чтения
    if( (infd = open(infile, O_RDONLY)) == -1 ) {
        fprintf(stderr, "Can't open file for reading...Exiting...\n");
        exit( EXIT_FAILURE );
    }

//создаём новый файл
    outfd = creat(outfile, 0644);

//цикл чтения блоками из файла
    while (read( infd, utf8_buffer, BUFSIZE ) > 0) {

        u32 i;

//сканируем полученные коды на предмет кириллических
        for( i = 0; i < BUFSIZE; ++i ) {

/*
is_cyrillic() проверяет, является ли символ кириллическим. Если да, то возвращает его адрес в таблице кириллических кодов

replace_array() подвигает содержимое буфера на один байт, начиная с позиции, следующей за найденным кириллическим символом, чтобы вместить туда utf-символ, т.к. он занимает на 1 байт больше, чем символ cp1251.

cp1251_to_utf8() собственно, занимается заменой найденного cp1251 кода на код utf8.

++total_utf8_symbols - увеличиваем общее число байт буфера, т.к. с каждым заменённым символом буфер увеличивается на один байт по сравнению с исходным буффером cp1251 символов.

++i - увеличиваем индекс просматриваемого элемента в буфере
*/

            if( ( CP1251 = is_cyrillic( utf8_buffer ) ) != NULL ) {
                replace_array( utf8_buffer, i + 1 );
                cp1251_to_utf8( CP1251, &utf8_buffer );
                ++total_utf8_symbols;
                ++i;
            }
        }

//пишем то, что получилось в файл.

        write( outfd, utf8_buffer, total_utf8_symbols );

    }
    close( infd );
    close( outfd );

return 0;
}


Если честно, я уже устал искать грабли. Если мы передаём этой программе маленький файл, содержащий кириллицу CP1251, формируемый файл получается перекодированным до определённого символа. Потом заполняет нулями. Не могу понять, от чего зависит расположение этого символа. Где там ошибка? А если большой файл - то вообще ошибка сегментации. Может быть нужно использовать потоки вместо описателей файлов? Всё-таки с символами же работаем, а не с кодами. Я не нашёл в сети нормальной спецификации рассматриваемых кодировок, и тот алгоритм, который я составил, основывается исключительно на анализе hex-кодов символов в различных кодировках. Так что, если кому-то неохота разбираться с примером, но есть линки, просьба постить. Возможно, ошибка связана с недостаточным пониманием(или непониманием) спецификации кодировок. Короче я запутался и не знаю, куда бежать! Просьба прокомментировать - где неоптимально, где грабли, где низачот!:)
361
04 сентября 2007 года
Odissey_
661 / / 19.09.2006
Цитата:
Решил написать консольную утилиту для перекодировки символов.


Хм... а iconv не смотрел? кстати там открытый исходник

8.9K
18 сентября 2007 года
Kulti
77 / / 29.07.2006
Пытаюсь использовать iconv:
 
Код:
char* in_buf, out_buf;
size_t in_sb, out_sb;
iconv_t cd = iconv_open( "UTF8", "CP1251" );
....
iconv( cd, &in_buf, &in_sb, &out_buf, &out_sb );
....
Может я конечно ман не полностью осознал, но переменные in_sb, out_sb я нулями ининциализирую. Конвертация происходит без ошибок, но результат пустая строка.
Кодировки точно правильные, я консольным iconv проверял.
361
18 сентября 2007 года
Odissey_
661 / / 19.09.2006
русский man по iconv здесь

на это смотрел -
 
Код:
[COLOR="Red"]char*[/COLOR] in_buf, [COLOR="Red"]out_buf[/COLOR];

out_buf просто char
8.9K
18 сентября 2007 года
Kulti
77 / / 29.07.2006
Цитата: Odissey_
русский man по iconv здесь

на это смотрел -
 
Код:
[COLOR="Red"]char*[/COLOR] in_buf, [COLOR="Red"]out_buf[/COLOR];

out_buf просто char

Ну описался я =) ( как тут ударение поставить =)) ) Я же не буду весь свой исходник класть. Сократил чуток и ошибся. За русский ман спасибо, теперь буду знать где если что-то не понятно почитать...

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог