Re: Кроссплатформенное преобразование wstring в string
От: Rakafon Украина http://rakafon.blogspot.com/
Дата: 17.07.08 17:03
Оценка: 3 (1)
Здравствуйте, Ubivetz, Вы писали:
U>Как можно кроссплатформенно преобразовать wstring в string?

Если надобно транслировать коджировки туда-сюда, например в данном случае UCS-2-INTERNAL (или UTF-16) в SOME_LOCAL_CHARSET и наоборот, то, имхо, лучшим решением окажется не написание всевозможных велосипедов, а использование проверенного кроссплатформенного решения: iconv POSIX-compliant charset conversion library.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Re: Кроссплатформенное преобразование wstring в string
От: Conr Россия  
Дата: 10.07.08 09:04
Оценка: 2 (1)
Здравствуйте, Ubivetz, Вы писали:

U>Как можно кроссплатформенно преобразовать wstring в string?

U>Пробую через codecvt но не получается. Может есть у кого рабочий код?
В первом приближении как-то так:
#include <string>
#include <locale>
#include <iostream>

std::string narrow(const std::wstring& wide, const std::locale& loc)
{
    if (wide.empty())
        return std::string();

    typedef std::wstring::traits_type::state_type state_type;
    typedef std::codecvt<wchar_t, char, state_type> CVT;

    const CVT& cvt = std::use_facet<CVT>(loc);
    std::string narrow(cvt.max_length()*wide.size(), '\0');
    state_type state = state_type();

    const wchar_t* from_beg = &wide[0];
    const wchar_t* from_end = from_beg + wide.size();
    const wchar_t* from_nxt;
    char* to_beg = &narrow[0];
    char* to_end = to_beg + narrow.size();
    char* to_nxt;

    std::string::size_type sz = 0;
    std::codecvt_base::result r;
    do
    {
        r = cvt.out(state, from_beg, from_end, from_nxt,
                           to_beg,   to_end,   to_nxt);
        switch (r)
        {
        case std::codecvt_base::error:
            throw std::runtime_error("error converting wstring to string");

        case std::codecvt_base::partial:
            sz += to_nxt - to_beg;
            narrow.resize(2*narrow.size());
            to_beg = &narrow[sz];
            to_end = &narrow[0] + narrow.size();
            break;

        case std::codecvt_base::noconv:
            narrow.resize(sz + (from_end-from_beg)*sizeof(wchar_t));
            std::memcpy(&narrow[sz], from_beg,(from_end-from_beg)*sizeof(wchar_t));
            r = std::codecvt_base::ok;
            break;

        case std::codecvt_base::ok:
            sz += to_nxt - to_beg;
            narrow.resize(sz);
            break;
        }
    } while (r != std::codecvt_base::ok);

    return narrow;
} 

int main(int argc, char* argv[])
{
    try
    {
        std::wstring wide(L"asdfasdf");
        std::string ansi = narrow(wide, std::locale() ); 

        std::locale loc_germany ("German_germany");
        std::wstring wgermany(L"\x00df - sharp-s");
        std::string agermany = narrow(wgermany, loc_germany); 

        std::locale loc_russian ("Russian");
        std::wstring wrussian(L"фигня всякая");
        std::string arussian = narrow(wrussian, loc_russian); 
    }
    catch(const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    return 0;
}
Re[3]: Кроссплатформенное преобразование wstring в string
От: Conr Россия  
Дата: 10.07.08 09:45
Оценка: 2 (1)
Здравствуйте, Ubivetz, Вы писали:

C>>std::string narrow(const std::wstring& wide, const std::locale& loc)

C>>{
C>>}[/ccode]

U>Обратное преобразование так же?


практически.
std::wstring widen(const std::string& narrow, const std::locale& loc)
{
    if (narrow.empty())
        return std::wstring();

    typedef std::string::traits_type::state_type state_type;
    typedef std::codecvt<wchar_t, char, state_type> CVT;
    const CVT& cvt = std::use_facet<CVT>(loc);
    std::wstring wide(narrow.size(), '\0');
    state_type state = state_type();
    const char* from_beg = &narrow[0];
    const char* from_end = from_beg + narrow.size();
    const char* from_nxt;
    wchar_t* to_beg = &wide[0];
    wchar_t* to_end = to_beg + wide.size();
    wchar_t* to_nxt;
    std::wstring::size_type sz = 0;
    std::codecvt_base::result r;
    do
    {
        r = cvt.in(state, from_beg, from_end, from_nxt,
                          to_beg,   to_end,   to_nxt);
        switch (r)
        {
        case std::codecvt_base::error:
            throw std::runtime_error("error converting string to wstring");
        case std::codecvt_base::partial:
            sz += to_nxt - to_beg;
            wide.resize(2*wide.size());
            to_beg = &wide[sz];
            to_end = &wide[0] + wide.size();
            break;
        case std::codecvt_base::noconv:
            wide.resize(sz + (from_end-from_beg));
            std::memcpy(&wide[sz], from_beg, (std::size_t)(from_end-from_beg));
            r = std::codecvt_base::ok;
            break;
        case std::codecvt_base::ok:
            sz += to_nxt - to_beg;
            wide.resize(sz);
            break;
        }
    } while (r != std::codecvt_base::ok);

   return wide;
}
Кроссплатформенное преобразование wstring в string
От: Ubivetz Украина  
Дата: 10.07.08 08:02
Оценка:
Привет всем!

Как можно кроссплатформенно преобразовать wstring в string?
Пробую через codecvt но не получается. Может есть у кого рабочий код?
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re: Кроссплатформенное преобразование wstring в string
От: StevenIvanov США  
Дата: 10.07.08 08:52
Оценка:
Здравствуйте, Ubivetz, Вы писали:

U>Привет всем!


U>Как можно кроссплатформенно преобразовать wstring в string?

U>Пробую через codecvt но не получается. Может есть у кого рабочий код?

Насколько я понимаю вопрос без специальных либ (типа ICU) не обойтись. С ними — можно.Насколько я помню юникод в лиукс-системах определен как 32-битное целое в отличие от 16-и битного в виндовс.
Re[2]: Кроссплатформенное преобразование wstring в string
От: Ytz https://github.com/mtrempoltsev
Дата: 10.07.08 09:00
Оценка:
ICU как вариант — но очень толстая.
Можно проще — все что наружу сохранять в utf8, внутри обычный basic_string<wchar_t> в котором в зависимости от размера wchar_t — 2 или 4 байта, лежит utf16 или utf32 соответственно.
Re[2]: Кроссплатформенное преобразование wstring в string
От: Ubivetz Украина  
Дата: 10.07.08 09:00
Оценка:
Здравствуйте, StevenIvanov, Вы писали:

SI>Здравствуйте, Ubivetz, Вы писали:


U>>Привет всем!


U>>Как можно кроссплатформенно преобразовать wstring в string?

U>>Пробую через codecvt но не получается. Может есть у кого рабочий код?

SI>Насколько я понимаю вопрос без специальных либ (типа ICU) не обойтись. С ними — можно.Насколько я помню юникод в лиукс-системах определен как 32-битное целое в отличие от 16-и битного в виндовс.

Ну...юникод вообще-то в современных Linux и MacOS X мультибайтный UTF-8.
Что интересно, sizeof(wchar_t) = 4 в Mac OS X 10.4.x
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re: Кроссплатформенное преобразование wstring в string
От: Аноним  
Дата: 10.07.08 09:07
Оценка:
Здравствуйте, Ubivetz, Вы писали:

U>Как можно кроссплатформенно преобразовать wstring в string?

U>Пробую через codecvt но не получается. Может есть у кого рабочий код?

#include <locale>
#include <string>

#include <iostream>

using namespace std;

string wstring2string(const wstring &source, locale const &loc = std::locale::classic()) {
string result(source.size(), char());
const ctype<char>& ct = use_facet<ctype<char> >(loc);
string::iterator dest(result.begin());
wstring::const_iterator it(source.begin());
wstring::const_iterator end(source.end());
for (; it != end; ++it, ++dest)
*dest = ct.narrow(*it, '\0');
return result;
}

int main() {
wstring s = L"This is a test";
cout << wstring2string(s) << endl;
}
Re[2]: Кроссплатформенное преобразование wstring в string
От: Ubivetz Украина  
Дата: 10.07.08 09:33
Оценка:
Здравствуйте, Conr, Вы писали:

C>Здравствуйте, Ubivetz, Вы писали:


U>>Как можно кроссплатформенно преобразовать wstring в string?

U>>Пробую через codecvt но не получается. Может есть у кого рабочий код?
C>В первом приближении как-то так:
C>#include <string>
C>#include <locale>
C>#include <iostream>

C>std::string narrow(const std::wstring& wide, const std::locale& loc)
C>{
C>    if (wide.empty())
C>        return std::string();

C>}


Большое спасибо! Работает!
Только можно вместо
std::locale loc_russian ("Russian");


написать
std::locale loc_russian ("");
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re[2]: Кроссплатформенное преобразование wstring в string
От: Ubivetz Украина  
Дата: 10.07.08 09:43
Оценка:
Здравствуйте, Conr, Вы писали:

C>Здравствуйте, Ubivetz, Вы писали:


U>>Как можно кроссплатформенно преобразовать wstring в string?

U>>Пробую через codecvt но не получается. Может есть у кого рабочий код?
C>В первом приближении как-то так:
C>#include <string>
C>#include <locale>
C>#include <iostream>

C>std::string narrow(const std::wstring& wide, const std::locale& loc)
C>{
C>}


Обратное преобразование так же?
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re[3]: Кроссплатформенное преобразование wstring в string
От: Conr Россия  
Дата: 10.07.08 09:43
Оценка:
Здравствуйте, Ubivetz, Вы писали:
U>Только можно вместо
U>
U>std::locale loc_russian ("Russian");
U>


U>написать

U>
U>std::locale loc_russian ("");
U>

Это если локаль по умолчанию русская, иначе исключение полетит.
Re[3]: Кроссплатформенное преобразование wstring в string
От: Кодт Россия  
Дата: 10.07.08 10:24
Оценка:
Здравствуйте, Ubivetz, Вы писали:

U>Ну...юникод вообще-то в современных Linux и MacOS X мультибайтный UTF-8.

U>Что интересно, sizeof(wchar_t) = 4 в Mac OS X 10.4.x

Это у всех gcc по умолчанию — чтобы туда UCS-4 влез.
Можно принудить к UTF-16/UCS-2 с помощью ключа -fshort-wchar
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: Кроссплатформенное преобразование wstring в string
От: zaufi Земля  
Дата: 10.07.08 11:44
Оценка:
Здравствуйте, Conr, Вы писали:

C>Здравствуйте, Ubivetz, Вы писали:


U>>Как можно кроссплатформенно преобразовать wstring в string?

U>>Пробую через codecvt но не получается. Может есть у кого рабочий код?
C>В первом приближении как-то так:
<SNIP>

зачем тока пользовать некошеный memcpy? std::copy для этого есть... в итоге конечно все равно буит memcpy, но код, imho, станет красивше )
Re[4]: Кроссплатформенное преобразование wstring в string
От: Ubivetz Украина  
Дата: 10.07.08 12:38
Оценка:
Здравствуйте, Conr, Вы писали:

C>Здравствуйте, Ubivetz, Вы писали:

U>>Только можно вместо
U>>
U>>std::locale loc_russian ("Russian");
U>>


U>>написать

U>>
U>>std::locale loc_russian ("");
U>>

C>Это если локаль по умолчанию русская, иначе исключение полетит.

Так заренее неизвестно, на какой локали будет запускаться программа, какой язык будет пареобразовываться.
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re: Кроссплатформенное преобразование wstring в string
От: Аноним  
Дата: 10.07.08 14:03
Оценка:
если не кроссплатформенно, то можно так

_bstr_t wstr(L"wchar");
string str = (char*)wstr;
Re[2]: Кроссплатформенное преобразование wstring в string
От: Ubivetz Украина  
Дата: 10.07.08 14:29
Оценка:
Здравствуйте, Аноним, Вы писали:

А>если не кроссплатформенно, то можно так


А>
А>_bstr_t wstr(L"wchar");
А>string str = (char*)wstr;
А>


Некроссплатформенно не нужно. Нужно чтобы работало как минимум на W2k-Vista и MacOS X 10.3.9+
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re[3]: Кроссплатформенное преобразование wstring в string
От: Conr Россия  
Дата: 10.07.08 15:08
Оценка:
Здравствуйте, Ubivetz, Вы писали:

U>Некроссплатформенно не нужно. Нужно чтобы работало как минимум на W2k-Vista и MacOS X 10.3.9+

В этом случае, кстати, будет лучше написать 2 реализации — под Win32 и MacOS, использующие родные функции преобразования:

Mac: CreateTextEncoding + CreateUnicodeToTextInfo + ConvertFromUnicodeToText + DisposeUnicodeToTextInfo
Win: WideCharToMultiByte

Работать будет надежнее, чем вышеприведенный код. Ну или, как минимум, понятнее.
Re: Кроссплатформенное преобразование wstring в string
От: k732  
Дата: 17.07.08 18:27
Оценка:
Здравствуйте, Ubivetz, Вы писали:

U>Привет всем!


U>Как можно кроссплатформенно преобразовать wstring в string?

U>Пробую через codecvt но не получается. Может есть у кого рабочий код?

либо boost::lexical_cast

либо руками

    template<class T, class A> std::wstring to_unicode(
        std::basic_string<char, T, A> const& in,
        std::locale const& loc = std::locale())
    {
        typedef std::codecvt<wchar_t, char, std::mbstate_t> facet;
        const facet& cvt = std::use_facet<facet>(loc);
    
        std::wstring out;
        out.reserve(in.length());
    
        facet::state_type state = facet::state_type();
        const char *ibuf = in.data(), *iend = in.data() + in.size();
        while(ibuf != iend)
        {
            wchar_t obuf[MAX_PATH], *oend;
            facet::result res = cvt.in (state, ibuf, iend, ibuf, obuf, obuf + MAX_PATH, oend = obuf);
            if( res == facet::error ) { state = facet::state_type(); ibuf += 1; }
            out.append(obuf, oend - obuf);
            if( res == facet::error ) out += L'?';
        }
        return out;
    }
    
    template<class T, class A> std::string to_multibyte(
        std::basic_string<wchar_t, T, A> const& in,
        std::locale const& loc = std::locale())
    {
        typedef std::codecvt<wchar_t,char,std::mbstate_t> facet;
        facet const& cvt = std::use_facet<facet>(loc);
    
        std::string out;
        out.reserve(in.length());
    
        facet::state_type state = facet::state_type();
        const wchar_t *ibuf = in.data(), *iend = in.data() + in.size();
        char obuf[MAX_PATH], *oend;
        while(ibuf != iend)
        {
            facet::result res = cvt.out(state, ibuf, iend, ibuf, obuf, obuf + MAX_PATH, oend = obuf);
            if( res == facet::error ) { state = facet::state_type(); ibuf += 1; }
            out.append(obuf, oend - obuf);
            if( res == facet::error ) out += L'?';
        }
        if( state == facet::partial )
        {
            cvt.unshift(state, obuf, obuf + MAX_PATH, oend = obuf);
            out.append (obuf, oend - obuf);
        }
        return out;
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.