Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 38, средняя оценка - 4.95
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
#1

iconv - C++

13.12.2012, 22:29. Просмотров 5533. Ответов 11
Метки нет (Все метки)

Есть такая библиотека как iconv для преобразования кодировок http://www.cyberforum.ru/blogs/131347/blog533.html
Стоит задача написать простенькую обвертку для преобразования utf8 в win1251 в плюсовом стиле вроде
C++
1
std::string utf8_to_win1251(const std::string& instr)
Но вот не могу найти нормально руководства где описывалось что и как http://www.gnu.org/software/libc/man...sion-Interface
C++
1
size_t iconv (iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
В общем непонятно что именно возвращает ф-ция, и почему параметры указатели на указатель, и почему размеры передаются тоже по адресу.

И главный вопрос как узнать какого размера нужен будет выходной буфер что бы все поместилось...

Набросок пока такой
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <string>
#include "iconv.h"
#pragma comment(lib,"iconv-bcb.lib") // либа под Builder
//---------------------------------------------------------------------------
namespace my{
//---------------------------------------------------------------------------
std::string utf8_to_win1251(const std::string& instr)
{
    iconv_t cd;
 
    cd = iconv_open("CP1251", "UTF-8");
    if( cd == (iconv_t)(-1) )
                         throw std::runtime_error("Не удалось открыть iconv");
 
    errno = 0;  // ???
    int se;
 
    size_t in_length= instr.length();
    size_t out_length = 4048; // ???
 
    const char* in_buf= instr.c_str();   // ???
    char* out_buf= new char[out_length];   // ???
 
    const char* in = in_buf;
    char* out = out_buf;
 
    size_t  k = iconv(cd, &in,   &in_length,
                                                &out,  &out_length );
    se = errno;   // ???
 
    if(k)  throw std::runtime_error("Ошибка в k=/=0 ");
    if(se)  throw std::runtime_error("Ошибка в errno");
 
    iconv_close(cd);
 
    std::string outstr(out_buf); 
 
    delete[] out_buf;  // ???
    return outstr;
}
//---------------------------------------------------------------------------
}
//---------------------------------------------------------------------------
Добавлено через 5 часов 2 минуты

Решил так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//---------------------------------------------------------------------------
namespace my{
//---------------------------------------------------------------------------
std::string utf8_to_win1251(const std::string& instr)
{
    std::string outstr;
    iconv_t cd;
 
    cd = iconv_open("CP1251", "UTF-8");
    if( cd == (iconv_t)(-1) )
                         throw std::runtime_error("Не удалось открыть дескриптор iconv");
 
    size_t in_size= instr.size();
    const char* in= instr.c_str();
 
    char out_buf[BUF_SIZE];
    char* out;
    size_t out_size;
 
    size_t  k;
 
    while(in_size > 0)
        {
            out = out_buf;
            out_size = BUF_SIZE;
 
            errno = 0;
            k = iconv(cd, &in,  &in_size, &out, &out_size );
 
            if(k == (size_t)-1 && errno) throw std::runtime_error("Ошибка");
            outstr.append(out_buf,BUF_SIZE-out_size);
        }
 
     if(iconv_close(cd)!=0 )
            std::runtime_error("Не удается закрыть дескриптор iconv");
 
return outstr;
}
//---------------------------------------------------------------------------
}
//---------------------------------------------------------------------------
Добавлено через 6 минут
Дело в том что ф-ция iconv() использует передаваемые ей параметры и изменяет их.

После её вызова outbytesleft, inbytesleft, уменьшаются на количество преобразованных символов, т.е. показывают сколько еще осталось в выходном буфере места и сколько осталось преобразовать символов в входной строке соответственно
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.12.2012, 22:29
Здравствуйте! Я подобрал для вас темы с ответами на вопрос iconv (C++):

Windows. iconv и командная строка - C++
Привет. В командной строке кодировка CP866 (через chcp проверял), код программы в UTF-8. Пытаюсь перекодировать UTF-8 строку в CP866...

Не работает iconv: Fatal error: Call to undefined function iconv()... - PHP
Доброе время суток! Подскажите пожалуйста, почему может не работать функция iconv? Версия php 5.1.6, установлен на системе...

PHPExcel Notice: iconv() [function.iconv]: Detected an illegal character in input string! - PHP
Блин задолбала эта библиотека!!! Выдает 2 ошибки!!! : Detected an illegal character in input string in...

ICONV - зачем нужна iconv.output_encoding и иже с ней? - PHP
Добрый вечер. Есть вопрос по расширению ICONV для преобразования кодировок. Кто-нибудь знает, для чего нужны переменные...

Iconv - PHP
Приветствую уважаемые форумчане. Не могу преобразовать кириллицу в UTF-8 с помощью iconv Есть код &lt;?php foreach (range('А','Я') as...

Функция iconv - C Linux
Что-то с iconv я делаю не так! #include &lt;gd.h&gt; #include &lt;iconv.h&gt; int Ic; // Индекс цвета /*-------------*/ void...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Wolkodav
603 / 456 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
13.12.2012, 22:58 #2
А вроде бы русские буквы в utf-8 и в 1251, их кода совпадают, а английские и цифры во всех кодировках одинаковые. Нет? Тогда вопрос, смысл перевода? Может я конечно на память и ошибаюсь( Просто в одно время писал определитель кодировки текста и перекодировщик в utf-8. Если мне память не изменяет, то там коды совпадают. Да и ещё, я работал с кодами символов тогда. муторно(
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
14.12.2012, 12:48  [ТС] #3
Цитата Сообщение от Wolkodav Посмотреть сообщение
А вроде бы русские буквы в utf-8 и в 1251, их кода совпадают, а английские и цифры во всех кодировках одинаковые. Нет? Т
Латиница везде одна и та же, а кириллица отличается, как и в KOИ-8 и в других кодировках
ForEveR
В астрале
Эксперт С++
7971 / 4733 / 321
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
14.12.2012, 13:10 #4
Я вот так писал в свое время.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    template <class CharT, class ExternCharT>
    std::codecvt_base::result convert(CharT*& in_pointer, size_t in_size, ExternCharT*& out_pointer, size_t out_size,
            const std::string& from_code, const std::string& to_code)
    {
        iconv_t converter = iconv_open(to_code.c_str(), from_code.c_str());
        if (converter == iconv_t(-1))
        {
            throw IconvError("Converter opening error: " + Impl::errno_open());
        }
        char* in_pointer_for_conv = (char*)in_pointer;
        char* out_pointer_for_conv = (char*)out_pointer;
        Impl::trace(in_pointer_for_conv, in_size, out_pointer_for_conv, out_size);
        size_t result = iconv(converter, &in_pointer_for_conv, &in_size, &out_pointer_for_conv, &out_size);
        Impl::trace(in_pointer_for_conv, in_size, out_pointer_for_conv, out_size);
        in_pointer = (CharT*)in_pointer_for_conv;
        out_pointer = (ExternCharT*)out_pointer_for_conv;
        if (result == size_t(-1))
        {
            Impl::errno_convert();
            iconv_close(converter);
            if (errno == E2BIG || errno == EINVAL)
            {
                return std::codecvt_base::partial;
            }
            return std::codecvt_base::error;
        }
        iconv_close(converter);
        return std::codecvt_base::ok;
    }
Но у меня используется эта обретка через std::codecvt.

К примеру перекодировка из ucs2 в utf8 и обратно.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
template<class CharT>
typename ucs2utf8codecvt<CharT>::result 
ucs2utf8codecvt<CharT>::do_out(std::mbstate_t& /* state */,
                        const intern_type* from,
                        const intern_type* from_end,
                        const intern_type*& from_next,
                        extern_type* to,
                        extern_type* to_end,
                        extern_type*& to_next) const
{
    to_next = to;
    from_next = from;
    size_t from_size = (from_end - from_next) * sizeof(intern_type);
    size_t to_size = (to_end - to_next) * sizeof(extern_type); 
    return convert(from_next, from_size, to_next, to_size, 
                    (ucs2_be ? "UCS-2BE" : "UCS-2LE"), "UTF-8");
 
} // do_out
 
template<class CharT>
typename ucs2utf8codecvt<CharT>::result 
ucs2utf8codecvt<CharT>::do_in(std::mbstate_t& /* state */,
                       const extern_type* from,
                       const extern_type* from_end,
                       const extern_type*& from_next,
                       intern_type* to,
                       intern_type* to_end,
                       intern_type*& to_next) const
{
    to_next = to;
    from_next = from;
    size_t to_size = (to_end - to) * sizeof(intern_type);
    size_t from_size = (from_end - from) * sizeof(extern_type);
    return Locale::Convert::convert(from_next, from_size, to_next, to_size, "UTF-8", 
                    (ucs2_be ? "UCS-2BE" : "UCS-2LE"));
} // do_in
Добавлено через 10 минут
Ну и само использование из класса converter типа такого:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    do
    {
      charT* to_next;
      const fromCharT* old_from_next = from_next;
      r = cvt.in(state, from_next, str.data() + str.length(), from_next, 
                 to_, to_ + toSize_, to_next);
      if (r == std::codecvt_base::noconv)
      {
         converted.append(no_conversion(str));
         break;
      }
      if (r == std::codecvt_base::partial && old_from_next == from_next)
      {
         r = std::codecvt_base::error;
      }
      converted.append(to_, static_cast<size_t>(to_next - to_));
    }
    while (r == std::codecvt_base::partial);
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
14.12.2012, 13:17  [ТС] #5
Это конечно забавно и я походу не совсем вьехал... но зачем было обворачивать если такое громосткое использование ?
ForEveR
В астрале
Эксперт С++
7971 / 4733 / 321
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
14.12.2012, 13:22 #6
Avazart, М. Ну у меня есть N codecvt классов, каждый производен от стандартного std::codecvt. Есть удобная обертка над iconv, где в одном месте все по факту конвертируется. Есть converterstream, в который выставляется codecvt (через imbue), у него есть метод str, в котором он конвертирует вообщем-то. Все работает быстро, красиво, удобно, надежно.) Работа с непосредственно iconv-ом в первом коде, остальное уже частности.

Так же в другом месте, где просто нужно конвертнуть, есть простенькая функция.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
std::string convert_encoding(const std::string& data, const std::string& from, const std::string& to)
{
   if (data.empty())
   {
      return std::string();
   }
   iconv_t convert_hnd = iconv_open(to.c_str(), from.c_str());
   if (convert_hnd == (iconv_t)(-1))
   {
      throw std::logic_error("unable to create convertion descriptor");
   }
 
   char* in_ptr = const_cast<char*>(data.c_str());
   std::size_t in_size = data.size();
   std::vector<char> outbuf(6 * data.size());
   char* out_ptr = &outbuf[0];
   std::size_t reverse_size = outbuf.size();
 
   std::size_t result = iconv(convert_hnd, &in_ptr, &in_size, &out_ptr, &reverse_size);
   iconv_close(convert_hnd);
   if (result == (std::size_t)(-1))
   {
      throw std::logic_error("unable to convert");
   }
   return std::string(outbuf.data(), outbuf.size() - reverse_size);
}
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
14.12.2012, 16:10  [ТС] #7
Собственно теперь понял что нифига не понял.

UCS2 это как я понимаю широкие символы типа UTF16. При чем оно тут ?
Или аналогично можно и utf-8 в cp1251 ?
ForEveR
В астрале
Эксперт С++
7971 / 4733 / 321
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
14.12.2012, 16:30 #8
Avazart, В любую из любой конечно же. Я просто привел пример как у меня идет работа с iconv.)
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
14.12.2012, 17:30  [ТС] #9
Что-то не могу найти места в коде где происходит повторный iconv если выходной буфер меньше чем входная строка.

Добавлено через 47 минут
C++
1
std::vector<char> outbuf(6 * data.size());
Типа сразу с 6-кратным запасом...

А почему именно вектор, чем черевато использовать сразу std::string как буфер ?
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
14.12.2012, 18:50  [ТС] #10
Вот блин, капитан очевидность нарисовался , где ты был раньше?

Добавлено через 2 минуты
Это про циклЫ
C++
1
2
3
4
5
6
7
8
9
10
11
while(in_size > 0)
        {
            out = out_buf;
            out_size = BUF_SIZE;
 
            errno = 0;
            k = iconv(cd, &in,  &in_size, &out, &out_size );
 
            if(k == (size_t)-1 && errno) throw std::runtime_error("Ошибка");
            outstr.append(out_buf,BUF_SIZE-out_size);
        }
Ptomaine
13 / 13 / 0
Регистрация: 22.10.2011
Сообщений: 35
14.12.2012, 18:56 #11
Да уж ) Извиняюсь. Факир был пьян )
Avazart
Эксперт С++
7152 / 5329 / 278
Регистрация: 10.12.2010
Сообщений: 23,584
Записей в блоге: 17
14.12.2012, 18:59  [ТС] #12
Я только не пойму одно почему у меня когда буфер мал возращает k = (size_t)-1, но errno = 0 ( нет ошибок )
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.12.2012, 18:59
Привет! Вот еще темы с ответами:

iconv для Windows - C++ Qt
Есть ли в Qt для Windows аналог функции iconv ? Просмотрел все хедеры, ничего похожего ни на iconv, ни на libiconv не нашел. Или хотя...

Can't locate Text/Iconv.pm - Perl
use Text::Iconv; Can't locate Text/Iconv.pm В чем дело?

Как правильно использовать iconv? - PHP
как правильно использовать iconv? суть такова - парсирую разные сайты и соответсвенно разные могут быть кодировки , причем даже иногда...

Правильно ли я реализовываю фунцию iconv? - PHP
Всем привет! Скажите пожалуйста правильно ли я реализовываю фунцию iconv? Ситуация следующая все страницы сайта в кодировке утф8, но...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
14.12.2012, 18:59
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru