Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Преобразование Ansi <-> Utf8


Автор: Alca 23.11.2009, 17:26
Надо выполнить преобразование Ansi <-> Utf8. Вот функции:
Код

//---------------------------------------------------------------------------
std::wstring sAnsiToUtf8(const std::string &csAnsiStr) {
    INT iLen = ::MultiByteToWideChar(CP_ACP, 0, csAnsiStr.c_str(), - 1, NULL, 0);
    
    if (iLen > 0) {        
        std::vector<wchar_t> vw(iLen);
        ::MultiByteToWideChar(CP_ACP, 0, csAnsiStr.c_str(), - 1, &vw[0], iLen);
        
        return &vw[0];
    } else {
        return L"";
    }
}
//---------------------------------------------------------------------------
std::string sUtf8ToAnsi(const std::wstring &csUtf8Str) {
    INT iLen = ::WideCharToMultiByte(CP_UTF8, 0, csUtf8Str.c_str(), - 1, NULL, 0, NULL, NULL);
    
    if (iLen > 0) {        
        std::vector<char> vw(iLen);
        ::WideCharToMultiByte(CP_UTF8, 0, csUtf8Str.c_str(), - 1, &vw[0], iLen, NULL, NULL);
        
        return &vw[0];
    } else {
        return "";
    }
}
//---------------------------------------------------------------------------


Тест:
Код

const std::string csAnsiStr = "Это АНСИ-строка...";                  

std::wstring wsRes;  
std::string  sRes;           

wsRes = sAnsiToUtf8(csAnsiStr);        //wsRes содержит "Это АНСИ-строка..."
sRes  = sUtf8ToAnsi(wsRes);            //sRes  содержит "Это АНСИ-строка..."
//
assert(csAnsiStr == sRes);            //валиться assert

Чего не так?

Автор: jonie 23.11.2009, 17:52
Цитата

Код

wsRes = sAnsiToUtf8(csAnsiStr);        //wsRes содержит "Это АНСИ-строка..."

так ведь это не UTF-8, это UCS2 (который урезанный UTF-16LE).
а вы потом хотите его конвертируете в UTF-8 функцией со странным названием "sUtf8ToAnsi".

Т.е. у вас сейчас две функции делают вот что: ANSI->UCS-2->UTF-8

Автор: Alca 23.11.2009, 18:05
Как правильно? Можно пример кода?

Автор: jonie 23.11.2009, 20:57
Цитата

 Conversion between UTF8 and ANSI codepage using WINAPI
For conversion between ANSI code page and UTF-8 can be used Windows API functions WideCharToMultiByte() and MultiByteToWideChar(). Both ways are very similar as you can see below.
There is only one problem for this method - you are limited to ANSI codepages installed on the system.
Conversion from ANSI to UTF-8

    * convert input ANSI string to widechar using MultiByteToWideChar(CP_ACP, ...) function (CP_ACP is current Windows system Ansi code page)
    * convert output widechar string from previous call to UTF-8 using WideCharToMultiByte(CP_UTF8, ...)  function

Conversion from UTF-8 to ANSI

    * convert input UTF-8 string to widechar using MultiByteToWideChar(CP_UTF8, ...) function
    * convert output widechar string from previous call to ANSI using WideCharToMultiByte(CP_ACP, ...)  function (CP_ACP is current Windows system Ansi code page)
стырено с http://voloda.bazilisek.net/conversion-between-utf8-and-ansi-codepage-using-winapi-bi33-a4c/index.html

Сами-то напишите?

кстати, вам не обязательно делать vector, можно использовать std::string::resize() в связке с &string.at(0) ...


Автор: Alca 23.11.2009, 22:11
Цитата

Сами-то напишите?

Спасибо, попробую. 
Цитата

кстати, вам не обязательно делать vector, можно использовать std::string::resize() в связке с &string.at(0) ...

 smile 

Автор: Alca 23.11.2009, 23:16
Попытка №2:
Код

//---------------------------------------------------------------------------
//TODO: - sAnsiToUtf8
/*
convert input ANSI string to widechar using MultiByteToWideChar(CP_ACP, ...) function (CP_ACP is current Windows system Ansi code page)
convert output widechar string from previous call to UTF-8 using WideCharToMultiByte(CP_UTF8, ...)  function
*/

std::wstring sAnsiToUtf8(const std::string &csAnsiStr) {
    CHAR  szUtf  [MAX_PATH] = {0};
    WCHAR wszTemp[MAX_PATH] = {0};

    INT iSize          = 0;
    INT iMultiByteSize = 0;

    iSize           = ::MultiByteToWideChar(CP_ACP,  0, csAnsiStr.c_str(), csAnsiStr.size(), NULL,    0); 
    /*DEBUG*/XASSERT_RET(0 < iSize, std::wstring());
    iSize           = ::MultiByteToWideChar(CP_ACP,  0, csAnsiStr.c_str(), csAnsiStr.size(), wszTemp, iSize);
    /*DEBUG*/XASSERT_RET(0 < iSize, std::wstring());


    iMultiByteSize  = ::WideCharToMultiByte(CP_UTF8, 0, wszTemp, iSize, NULL,  0,              NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::wstring());

    iMultiByteSize  = ::WideCharToMultiByte(CP_UTF8, 0, wszTemp, iSize, szUtf, iMultiByteSize, NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::wstring());

    szUtf[iMultiByteSize] = '\0'; 
    return (LPCWSTR)&szUtf[0];

    //return (LPCWSTR) &std::string(szUtf, iMultiByteSize).at(0);
}
//---------------------------------------------------------------------------
//TODO: - sUtf8ToAnsi
/*
convert input UTF-8 string to widechar using MultiByteToWideChar(CP_UTF8, ...) function
convert output widechar string from previous call to ANSI using WideCharToMultiByte(CP_ACP, ...)  function (CP_ACP is current Windows system Ansi code page)
*/
std::string sUtf8ToAnsi(const std::wstring &csUtf8Str) {
    //norm - входная строка
    //utf- выходная
    CHAR  szUtf  [MAX_PATH] = {0};
    WCHAR wszTemp[MAX_PATH] = {0};

    INT iSize          = 0;
    INT iMultiByteSize = 0;

    iSize           = ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)csUtf8Str.data(), csUtf8Str.size(), NULL,    0); 
    /*DEBUG*/XASSERT_RET(0 < iSize, std::string());

    iSize           = ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)csUtf8Str.data(), csUtf8Str.size(), wszTemp, iSize); 
    /*DEBUG*/XASSERT_RET(0 < iSize, std::string());



    iMultiByteSize  = ::WideCharToMultiByte(CP_ACP,  0, wszTemp, iSize, NULL,  0,              NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::string());

    iMultiByteSize  = ::WideCharToMultiByte(CP_ACP,  0, wszTemp, iSize, szUtf, iMultiByteSize, NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::string());

    szUtf[iMultiByteSize] = '\0';
    return std::string(szUtf);        //

    //return std::string(szUtf, iMultiByteSize);
}


Код

        const std::string csAnsiStr = "Это АНСИ-строка...";                  

        std::wstring wsRes;  
        std::string  sRes;           

        wsRes = sAnsiToUtf8(csAnsiStr);           //<<<<<<<< "귐苑뻐퀠킐킝킡⶘臑苑胑뻐뫐냐⸮."
        sRes  = sUtf8ToAnsi(wsRes);                  //<<<<<<<< "Это АНСИ-"
        XASSERT(csAnsiStr == sRes);

строка не поностью конвертиться.... Где косяк?

Автор: 586 24.11.2009, 01:11
Код
#include <windows.h>
#include <tchar.h>
#include <iostream>
std::wstring strtows(const std::string &str, UINT codePage)
{
    std::wstring ws;
    int n = MultiByteToWideChar(codePage, 0, str.c_str(), str.size()+1, /*dst*/NULL, 0);
    if(n)
    {
        ws.resize(n-1);
        if(MultiByteToWideChar(codePage, 0, str.c_str(), str.size()+1, /*dst*/&ws[0], n) == 0)
            ws.clear();
    }
    return ws;
}
std::string wstostr(const std::wstring &ws, UINT codePage)
{
    std::string str;
    int n = WideCharToMultiByte(codePage, 0, ws.c_str(), ws.size()+1, /*dst*/NULL, 0, /*defchr*/0, NULL);
    if(n)
    {
        str.resize(n-1);
        if(WideCharToMultiByte(codePage, 0, ws.c_str(), ws.size()+1, /*dst*/&str[0], n, /*defchr*/0, NULL) == 0)
            str.clear();
    }
    return str;
}
std::string chcp(const std::string &str, UINT codePageSrc, UINT codePageDst)
{
    return wstostr(strtows(str, codePageSrc), codePageDst);
}
int main(int argc, char* argv[])
{
    std::string strAcpSrc = "ANSI строка";
    std::string strUtf = chcp(strAcpSrc, CP_ACP, CP_UTF8);
    std::string strAcp = chcp(strUtf, CP_UTF8, CP_ACP);
    std::cout << ((strAcpSrc == strAcp) ? "success" : "error");
    std::cin.get();
    return 0;
}

Автор: Alca 24.11.2009, 11:33
586, спасибо, работает. 
Я понял, где у меня была ошибка:
Надо было вместо:
Код

std::wstring sAnsiToUtf8(const std::string &csAnsiStr) {
...

написать:
Код

std::string sAnsiToUtf8(const std::string &csAnsiStr) {
...

Вот тоже рабочий код (хотя с буферами нехорошо будет):
Код

//---------------------------------------------------------------------------
//TODO: + sAnsiToUtf8
/*
convert input ANSI string to widechar using MultiByteToWideChar(CP_ACP, ...) function (CP_ACP is current Windows system Ansi code page)
convert output widechar string from previous call to UTF-8 using WideCharToMultiByte(CP_UTF8, ...)  function
*/

std::string sAnsiToUtf8(const std::string &csAnsiStr) {
    CHAR  szUtf  [1024] = {0};
    WCHAR wszTemp[1024] = {0};

    INT iSize          = 0;
    INT iMultiByteSize = 0;

    iSize           = ::MultiByteToWideChar(CP_ACP,  0, csAnsiStr.c_str(), csAnsiStr.size(), NULL,    0); 
    /*DEBUG*/XASSERT_RET(0 < iSize, std::string());
    iSize           = ::MultiByteToWideChar(CP_ACP,  0, csAnsiStr.c_str(), csAnsiStr.size(), wszTemp, iSize);
    /*DEBUG*/XASSERT_RET(0 < iSize, std::string());


    iMultiByteSize  = ::WideCharToMultiByte(CP_UTF8, 0, wszTemp, iSize, NULL,  0,              NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::string());

    iMultiByteSize  = ::WideCharToMultiByte(CP_UTF8, 0, wszTemp, iSize, szUtf, iMultiByteSize, NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::string());

    //szUtf[iMultiByteSize] = '\0'; 
    //return (LPCWSTR)&szUtf[0];

    std::string sRes = szUtf;


    //return (LPCWSTR) (& (std::string(szUtf, iMultiByteSize).at(0)));

    return &szUtf[0];
}
//---------------------------------------------------------------------------
//TODO: + sUtf8ToAnsi
/*
convert input UTF-8 string to widechar using MultiByteToWideChar(CP_UTF8, ...) function
convert output widechar string from previous call to ANSI using WideCharToMultiByte(CP_ACP, ...)  function (CP_ACP is current Windows system Ansi code page)
*/
std::string sUtf8ToAnsi(const std::string &csUtf8Str) {
    //norm - входная строка
    //utf- выходная
    CHAR  szUtf  [1024] = {0};
    WCHAR wszTemp[1024] = {0};

    INT iSize          = 0;
    INT iMultiByteSize = 0;

    iSize           = ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)csUtf8Str.data(), csUtf8Str.size(), NULL,    0); 
    /*DEBUG*/XASSERT_RET(0 < iSize, std::string());

    iSize           = ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)csUtf8Str.data(), csUtf8Str.size(), wszTemp, iSize); 
    /*DEBUG*/XASSERT_RET(0 < iSize, std::string());



    iMultiByteSize  = ::WideCharToMultiByte(CP_ACP,  0, wszTemp, iSize, NULL,  0,              NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::string());

    iMultiByteSize  = ::WideCharToMultiByte(CP_ACP,  0, wszTemp, iSize, szUtf, iMultiByteSize, NULL, NULL); 
    /*DEBUG*/XASSERT_RET(0 < iMultiByteSize, std::string());

    return std::string(szUtf, iMultiByteSize);
}
//---------------------------------------------------------------------------

Автор: Velud 17.5.2012, 16:53
а как конвертировать не wide char а обычную однобайтовую?

Автор: xvr 17.5.2012, 18:39
Цитата(Velud @  17.5.2012,  16:53 Найти цитируемый пост)
а как конвертировать не wide char а обычную однобайтовую? 

- А теперь мы попросим нашего глубокоуважаемого гостя сыграть нам 'Лунную сонату'
- Как, еще раз ?!

PS. Сделайте свою тему - нехорошо реанимировать 3х летний труп  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)