MFC,unicode转utf-8编码出错

时间:2021-07-23 20:16:53
CString CExonDlg::UnicodeToUTF_8First(CString str)
{   
int u8Len =WideCharToMultiByte(CP_UTF8, NULL,str,str.GetLength(), NULL, 0, NULL, FALSE);
char* szU8 = new  char[u8Len + 1];
int  hh=WideCharToMultiByte(CP_UTF8,NULL,str, str.GetLength(), szU8, u8Len, NULL, FALSE);
szU8[u8Len] = '\0';
CString str_utf=CString(szU8);
delete szU8;
return str_utf;  
}
将unicode转成utf-8,汉字个数是偶数的时候正常,奇数的时候,最后一个字符就五法实现转码,
比如:我输入“你好”编码之后结果正常
            但是”周州林“编码之后的结果就是”周州“
在网上查了WideCharToMultiByte的第四个参数(缓存区的字符个数),在第一次调用这个函数的地方,改成str.GetLength()+1,结果发现奇数个汉字正常了,但是偶数个汉字后面,最后一个汉字后面就加上了一个?,后来该成了str.GetLength()+2
发现他在处理数字和中文字符混合的字符串的字符串时,又出现了问题。
资料:unicode  汉字是2个字节,utf-8 汉字是3个字节。

10 个解决方案

#1


CString str_utf=CString(szU8);

这句是错误的。

#2


涉及到utf-8和unicode最好就别用CString了,不明了
下面的函数出去后记得使用delete []释放pOutBuf。
bool UnicodeToUtf8(const wchar_t* buf, char * & pOutBuf)
{
if (buf == NULL)
{
return NULL ;
}
int nLen = ::WideCharToMultiByte (CP_UTF8, 0, buf, -1, NULL, 0, NULL, NULL);
pOutBuf = new char[nLen+1] ;
ZeroMemory (pOutBuf, nLen + 1) ;
::WideCharToMultiByte (CP_UTF8, 0, buf, -1, pOutBuf, nLen, NULL, NULL);

return true;
}

#3


可以使用iconv开源库,支持非常多的语言及字符集

#4


CString str_utf=CString(szU8);
这个不是类型转换吗?他错在哪里呢?

#5


主要是,我现在传入的是一个cstring的字符串,要求我传出的也是一个字符串

#6


已经将第四个参数修改为-1但是还是会遇到同样的问题。

#7


int WideCharToMultiByte(
UINT CodePage, //指定执行转换的代码页
DWORD dwFlags, //允许你进行额外的控制,它会影响使用了读音符号(比如重音)的字符
LPCWSTR lpWideCharStr, //指定要转换为宽字节字符串的缓冲区
int cchWideChar, //指定由参数lpWideCharStr指向的缓冲区的字符个数
LPSTR lpMultiByteStr, //指向接收被转换字符串的缓冲区
int cchMultiByte, //指定由参数lpMultiByteStr指向的缓冲区最大值
LPCSTR lpDefaultChar, //遇到一个不能转换的宽字符,函数便会使用pDefaultChar参数指向的字符
LPBOOL pfUsedDefaultChar //至少有一个字符不能转换为其多字节形式,函数就会把这个变量设为TRUE
);

#8


这个函数仔细看过
UINT CodePage, //指定执行转换的代码页                                                              //   unicode转为utf-8     所以使用CP_UTF8
DWORD dwFlags, //允许你进行额外的控制,它会影响使用了读音符号(比如重音)的字符     //不进行额外的处理,所以为null
LPCWSTR lpWideCharStr, //指定要转换为宽字节字符串的缓冲区                     //str是我要转换的字符串
int cchWideChar, //指定由参数lpWideCharStr指向的缓冲区的字符个数             //unicode编码时,str.getlength()函数的返回值为字符数
LPSTR lpMultiByteStr, //指向接收被转换字符串的缓冲区           //第一次调用为null    第二次为szU8
int cchMultiByte, //指定由参数lpMultiByteStr指向的缓冲区最大值            //第一次调用为0    第二次为u8Len
LPCSTR lpDefaultChar, //遇到一个不能转换的宽字符,函数便会使用pDefaultChar参数指向的字符       //NULL,默认的指向字符是?
LPBOOL pfUsedDefaultChar //至少有一个字符不能转换为其多字节形式,函数就会把这个变量设为TRUE    //将这个变量设为TRUE,变异出错,因为他要求的是一个int    不是LPBOOL型

#9


你应该先把CString转换成Unicode,再转换成UTF-8
再默认的VC编译参数下,CString本身是MBCS的不是Unicode。所以计算长度会出错。

任何编码的字符串,转换到UTF-8,都要先to unicode,在utf-8

#10


    入参传递引用过去,也是出参,供参考
    void ConvertANSIToUTF8(CString &strANSI)   
    {   
    // CString to Unicode
    int nLen = ::MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,(LPCTSTR)strANSI,-1,NULL,0);   
    unsigned short * wszUTF_8 = new unsigned short[nLen+1];   
    memset(wszUTF_8, 0, nLen * 2 + 2);   
    nLen = MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strANSI, -1, wszUTF_8, nLen);   
      
    // Unicode to UTF-8
    nLen = WideCharToMultiByte(CP_UTF8, 0, wszUTF_8, -1, NULL, 0, NULL, NULL);   
        char *szUTF8=new char[nLen + 1];   
        memset(szUTF8, 0, nLen + 1);   
        WideCharToMultiByte (CP_UTF8, 0, wszUTF_8, -1, szUTF8, nLen, NULL,NULL);   
    strANSI = szUTF8;   
    delete wszUTF_8;   
    delete szUTF8;   
    }   

#1


CString str_utf=CString(szU8);

这句是错误的。

#2


涉及到utf-8和unicode最好就别用CString了,不明了
下面的函数出去后记得使用delete []释放pOutBuf。
bool UnicodeToUtf8(const wchar_t* buf, char * & pOutBuf)
{
if (buf == NULL)
{
return NULL ;
}
int nLen = ::WideCharToMultiByte (CP_UTF8, 0, buf, -1, NULL, 0, NULL, NULL);
pOutBuf = new char[nLen+1] ;
ZeroMemory (pOutBuf, nLen + 1) ;
::WideCharToMultiByte (CP_UTF8, 0, buf, -1, pOutBuf, nLen, NULL, NULL);

return true;
}

#3


可以使用iconv开源库,支持非常多的语言及字符集

#4


CString str_utf=CString(szU8);
这个不是类型转换吗?他错在哪里呢?

#5


主要是,我现在传入的是一个cstring的字符串,要求我传出的也是一个字符串

#6


已经将第四个参数修改为-1但是还是会遇到同样的问题。

#7


int WideCharToMultiByte(
UINT CodePage, //指定执行转换的代码页
DWORD dwFlags, //允许你进行额外的控制,它会影响使用了读音符号(比如重音)的字符
LPCWSTR lpWideCharStr, //指定要转换为宽字节字符串的缓冲区
int cchWideChar, //指定由参数lpWideCharStr指向的缓冲区的字符个数
LPSTR lpMultiByteStr, //指向接收被转换字符串的缓冲区
int cchMultiByte, //指定由参数lpMultiByteStr指向的缓冲区最大值
LPCSTR lpDefaultChar, //遇到一个不能转换的宽字符,函数便会使用pDefaultChar参数指向的字符
LPBOOL pfUsedDefaultChar //至少有一个字符不能转换为其多字节形式,函数就会把这个变量设为TRUE
);

#8


这个函数仔细看过
UINT CodePage, //指定执行转换的代码页                                                              //   unicode转为utf-8     所以使用CP_UTF8
DWORD dwFlags, //允许你进行额外的控制,它会影响使用了读音符号(比如重音)的字符     //不进行额外的处理,所以为null
LPCWSTR lpWideCharStr, //指定要转换为宽字节字符串的缓冲区                     //str是我要转换的字符串
int cchWideChar, //指定由参数lpWideCharStr指向的缓冲区的字符个数             //unicode编码时,str.getlength()函数的返回值为字符数
LPSTR lpMultiByteStr, //指向接收被转换字符串的缓冲区           //第一次调用为null    第二次为szU8
int cchMultiByte, //指定由参数lpMultiByteStr指向的缓冲区最大值            //第一次调用为0    第二次为u8Len
LPCSTR lpDefaultChar, //遇到一个不能转换的宽字符,函数便会使用pDefaultChar参数指向的字符       //NULL,默认的指向字符是?
LPBOOL pfUsedDefaultChar //至少有一个字符不能转换为其多字节形式,函数就会把这个变量设为TRUE    //将这个变量设为TRUE,变异出错,因为他要求的是一个int    不是LPBOOL型

#9


你应该先把CString转换成Unicode,再转换成UTF-8
再默认的VC编译参数下,CString本身是MBCS的不是Unicode。所以计算长度会出错。

任何编码的字符串,转换到UTF-8,都要先to unicode,在utf-8

#10


    入参传递引用过去,也是出参,供参考
    void ConvertANSIToUTF8(CString &strANSI)   
    {   
    // CString to Unicode
    int nLen = ::MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,(LPCTSTR)strANSI,-1,NULL,0);   
    unsigned short * wszUTF_8 = new unsigned short[nLen+1];   
    memset(wszUTF_8, 0, nLen * 2 + 2);   
    nLen = MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strANSI, -1, wszUTF_8, nLen);   
      
    // Unicode to UTF-8
    nLen = WideCharToMultiByte(CP_UTF8, 0, wszUTF_8, -1, NULL, 0, NULL, NULL);   
        char *szUTF8=new char[nLen + 1];   
        memset(szUTF8, 0, nLen + 1);   
        WideCharToMultiByte (CP_UTF8, 0, wszUTF_8, -1, szUTF8, nLen, NULL,NULL);   
    strANSI = szUTF8;   
    delete wszUTF_8;   
    delete szUTF8;   
    }