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

iconv - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 38, средняя оценка - 4.95
Avazart
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
13.12.2012, 22:29     iconv #1
Есть такая библиотека как 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
Посмотрите здесь:

Can't locate Text/Iconv.pm Perl
Функция iconv C Linux
Не работает iconv: Fatal error: Call to undefined function iconv()... PHP
C/iconv,zlib,glut
C++ Qt iconv для Windows
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Wolkodav
 Аватар для Wolkodav
599 / 452 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
13.12.2012, 22:58     iconv #2
А вроде бы русские буквы в utf-8 и в 1251, их кода совпадают, а английские и цифры во всех кодировках одинаковые. Нет? Тогда вопрос, смысл перевода? Может я конечно на память и ошибаюсь( Просто в одно время писал определитель кодировки текста и перекодировщик в utf-8. Если мне память не изменяет, то там коды совпадают. Да и ещё, я работал с кодами символов тогда. муторно(
Avazart
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
14.12.2012, 12:48  [ТС]     iconv #3
Цитата Сообщение от Wolkodav Посмотреть сообщение
А вроде бы русские буквы в utf-8 и в 1251, их кода совпадают, а английские и цифры во всех кодировках одинаковые. Нет? Т
Латиница везде одна и та же, а кириллица отличается, как и в KOИ-8 и в других кодировках
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
14.12.2012, 13:10     iconv #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
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
14.12.2012, 13:17  [ТС]     iconv #5
Это конечно забавно и я походу не совсем вьехал... но зачем было обворачивать если такое громосткое использование ?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
14.12.2012, 13:22     iconv #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
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
14.12.2012, 16:10  [ТС]     iconv #7
Собственно теперь понял что нифига не понял.

UCS2 это как я понимаю широкие символы типа UTF16. При чем оно тут ?
Или аналогично можно и utf-8 в cp1251 ?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
14.12.2012, 16:30     iconv #8
Avazart, В любую из любой конечно же. Я просто привел пример как у меня идет работа с iconv.)
Avazart
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
14.12.2012, 17:30  [ТС]     iconv #9
Что-то не могу найти места в коде где происходит повторный iconv если выходной буфер меньше чем входная строка.

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

А почему именно вектор, чем черевато использовать сразу std::string как буфер ?
Avazart
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
14.12.2012, 18:50  [ТС]     iconv #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
 Аватар для Ptomaine
13 / 13 / 0
Регистрация: 22.10.2011
Сообщений: 35
14.12.2012, 18:56     iconv #11
Да уж ) Извиняюсь. Факир был пьян )
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.12.2012, 18:59     iconv
Еще ссылки по теме:

PHP PHPExcel Notice: iconv() [function.iconv]: Detected an illegal character in input string!
ICONV - зачем нужна iconv.output_encoding и иже с ней? PHP
Iconv PHP

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

Или воспользуйтесь поиском по форуму:
Avazart
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
14.12.2012, 18:59  [ТС]     iconv #12
Я только не пойму одно почему у меня когда буфер мал возращает k = (size_t)-1, но errno = 0 ( нет ошибок )
Yandex
Объявления
14.12.2012, 18:59     iconv
Ответ Создать тему
Опции темы

Текущее время: 04:12. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru