unicode 转换成UTF-8出现问题。

fjfzb 2008-12-17 05:01:39
我自己用basic_string基准编写了一个sString,我将字符串从UTF-8转换成UNICODE后,wchar_t*类型的值无法赋值给sString,具体代码如下:
struct sString : public std::basic_string<TCHAR> ,public std::basic_string<WCHAR>
{
public:
inline sString()
{
}

inline sString(const sString &a)
{
operator = (a);
}

inline sString(const TCHAR *str)
: std::basic_string<TCHAR>(str)
{

}

inline sString(const WCHAR* str)
: std::basic_string<WCHAR>(str)
{

}

inline void printf(const TCHAR *format,...)
{
TCHAR buff[ 255];

va_list ap;

va_start( ap, format);
_vstprintf( buff, format, ap);
va_end( ap);

std::basic_string<TCHAR>::operator =( buff);
}

inline operator LPCTSTR()
{
return (LPCTSTR)std::basic_string<TCHAR>::data();
}

inline operator LPCWSTR()
{
return (LPCWSTR)std::basic_string<WCHAR>::data();
}

inline void operator = (const std::basic_string<TCHAR> &a)
{
std::basic_string<TCHAR>::operator =( a);
}

inline void operator = (const TCHAR *str) {
std::basic_string<TCHAR>::operator =(str);
}

inline void operator = (const sString &a) {
std::basic_string<TCHAR>::operator =(a);
}

inline void operator = (const WCHAR* str)
{
std::basic_string<WCHAR>::operator =(str);
}

inline void operator = (const std::wstring &t)
{
std::basic_string<WCHAR>::operator =(t);
}
}
这里重写的sString 。下面是UNICODE转换UTF-8代码。
sString Utf8ToUnicode(LPCSTR szUft8)
{
sString szUnicode = _T("");
// UTF8 to Unicode
// 预转换,得到所需空间的大小
int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szUft8, strlen(szUft8), NULL, 0 );
// 分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间
wchar_t * wszString = new wchar_t[wcsLen+1];
memset(wszString,0x00,wcsLen+1);
// 转换
::MultiByteToWideChar(CP_UTF8, NULL, szUft8, strlen(szUft8), wszString, wcsLen);
// 最后加上'\0'
wszString[wcsLen] = '\0' ;

//这里出现问题,wszString转换出来正常,但是赋值给szUnicode 时,szUnicode 是空的。
szUnicode = wszString;


//delete
//*
if(wszString){
delete wszString;
wszString = NULL;
}
//*/
return szUnicode;
}

哪位大侠帮忙看看,小弟急用。
...全文
1734 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
fjfzb 2008-12-26
  • 打赏
  • 举报
回复
我现在正常用你说的方法修改,不过怎样去正确获取UNICODE字符串的字符码?我对字符串作这样的操作:

WCHAR *pCur = L“飞黄腾达”

while( *pCur != '\0')
{
UINT nChar = 0;

if( IsDBCSLeadByte( *pCur))
{
nChar = (BYTE)(*pCur++);
nChar <<= 8;
}
else
nChar = (BYTE)*pCur++;

。。。。。。

}


L“飞黄腾达”这4个字的字符串在内存里面保存应该是
39134
40644
33150
36798
0
通过上面的方法,nChar 获得的值并不正确,而且用IsDBCSLeadByte函数截取字符也有问题。帮我看一下问题出在哪里?
fjfzb 2008-12-26
  • 打赏
  • 举报
回复
我现在正常用你说的方法修改,不过怎样去正确获取UNICODE字符串的字符码?我对字符串作这样的操作:

WCHAR *pCur = L“飞黄腾达”

while( *pCur != '\0')
{
UINT nChar = 0;

if( IsDBCSLeadByte( *pCur))
{
nChar = (BYTE)(*pCur++);
nChar <<= 8;
}
else
nChar = (BYTE)*pCur++;

。。。。。。

}


L“飞黄腾达”这4个字的字符串在内存里面保存应该是
39134
40644
33150
36798
0
通过上面的方法,nChar 获得的值并不正确,而且用IsDBCSLeadByte函数截取字符也有问题。帮我看一下问题出在哪里?
fjfzb 2008-12-26
  • 打赏
  • 举报
回复
问题已基本解决,万分感谢楼上的大侠。
引力场变动源 2008-12-26
  • 打赏
  • 举报
回复
WCHAR或者wchar_t其实就是unsigned short,每一个字符一个unsigned short,不管是英文字母还是汉字,不需要额外的判断和转换,所以你可以把这种字符串看成是一个unsigned short的数据,对于你那个例子来说,第i个字符的编码就是pCur[i].
引力场变动源 2008-12-23
  • 打赏
  • 举报
回复
说起来,我没有做过UTF-8的程序呢,要么用的是Ascii极其扩展,要么像最近几年这样用的都是Unicode的。
对于Windows的API来说,可能没有办法区分Ascii和UTF-8的吧,因为两者都是char*的。

还有就是,即使工程不是Unicode的,也一样可以用Unicode的,比如修改窗体标题,默认用的是SetWindowText,在多字节环境下这个函数实际是通过宏映射到了SetWindowTextA,如果要用Unicode的话,可以绕过SetWindowText直接使用SetWindowTextW。 其它很多API函数也一样的,在后面加一个“W”就可以了。所以实在不行可以用这个办法,把字符串转换成Unicode版本以后再显示。
fjfzb 2008-12-23
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 Silenker 的回复:]
如果正确的进行了转换却还是显示乱码的话,的确是奇怪的事情。我以前遇到过一次,调试了很长时间也找不到原因,后来才发现,我以为是UTF-8的字符串,实际上却是GB2312的,UTF-8和GB2312都是多字节的,但是前者是Unicode的,后者却属于ASCII的扩展,所以换成ASCII与Unicode的转换问题就解决了。如果你能保证你的转换方法正确结果却是乱码的话,最好也看一下,你用的是不是GB2312或者其它的ASCII扩展。
[/Quote]

你在做这个的时候,是通过什么方式来转换成UTF8的,转换成UTF8的字符串又是怎么处理的。
我始终觉得,既然UTF8也算是一种国际标准,Windows的API应该也支持。像网站的处理几乎都是用UTF8的。
引力场变动源 2008-12-23
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 fjfzb 的回复:]
保存文件的时候自动将格式转成UTF8了。但是从文件里面读出来的时候好像又变回乱码了。
[/Quote]
所以我觉得,应该是Windows的API不支持直接使用UTF-8,只能在Ascii或者Unicode(UTF-16)里面选择一个。
fjfzb 2008-12-23
  • 打赏
  • 举报
回复
保存文件的时候自动将格式转成UTF8了。但是从文件里面读出来的时候好像又变回乱码了。
引力场变动源 2008-12-23
  • 打赏
  • 举报
回复
上面的那个程序里面,asc、unicode和utf16的内容都正确,utf8的内容是乱码,但是写入文件之后文件的内容没有乱码。
引力场变动源 2008-12-23
  • 打赏
  • 举报
回复
我直接用的STL的fstream写的,代码是下面这样的:


#include "stdafx.h"
#include "windows.h"
#include <string>
#include <fstream>
#include <iostream>
using namespace std;


//从Unicode到UTF8
string ToUTF8(wstring str)
{
char* buff;
int buffersize=WideCharToMultiByte(CP_UTF8,0,str.c_str(),(int)str.length(),0,0,0,0); //获取需要的输出缓冲区长度
buff=new char[buffersize+1];
WideCharToMultiByte(CP_UTF8,0,str.c_str(),(int)str.length(),buff,buffersize+1,0,0);
buff[buffersize]=0;
string utf=buff;
delete []buff;
return(utf);
}

//从Unicode到Ansi
string ToString(wstring str)
{
char *buff=new char[str.length()+1];
int i=WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),buff,str.length()+1,0,0);
buff[i]=0;
string text=buff;
delete [] buff;
return(text);
}

//从UTF8到Unicode
wstring FromUTF8(string utf)
{
wchar_t *buff=new wchar_t[utf.length()+1];
int i=MultiByteToWideChar(CP_UTF8, 0, utf.c_str(),-1, buff, (int)utf.length());
buff[i+1]=0;
wstring str=buff;
delete [] buff;
return(str);
}

//从Ansi到Unicode
wstring ToString(string str)
{
wchar_t *buff=new wchar_t[str.length()+1];
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buff, str.length()+1);
wstring text=buff;
delete [] buff;
return(text);
}

void main()
{
string asc="abcd这是一个ASCII字符串";
wstring unicode=ToString(asc); //toString有两个重载,分别是Ascii to Unicode 和Unicode to Ascii
string utf8=ToUTF8(unicode);
wstring utf16=FromUTF8(utf8);

ofstream ofs("D:\\01.txt");
ofs<<utf8.c_str()<<'\n';
ofs.close();

system("pause");
}

fjfzb 2008-12-23
  • 打赏
  • 举报
回复
你在输出到文件的时候,是否要先写UTF8的头标识(0xbfbbef)?
引力场变动源 2008-12-22
  • 打赏
  • 举报
回复
我测试了一下,转换成UTF8以后的确是乱码,但是从这个乱码的UTF8再转换为Unicode之后却又是正常的。
然后把乱码的字符串输出到文件之后,文件中的内容显示正确,没有乱码。

猜测:Windows只支持Ascii和Unicode(UTF-16)这两种编码方式,不能直接支持UTF-8,如果向Win32 API传递UTF-8字符串,会被自动当成Ascii字符串处理,因此产生乱码。
wgm001 2008-12-20
  • 打赏
  • 举报
回复
稍做改改,应该可以...
wgm001 2008-12-20
  • 打赏
  • 举报
回复

template<typename InputIterator, typename OutputIterator>
void encode_wchar(InputIterator iter, OutputIterator &dest)
{
if(*iter <= 0x007F)
{
*dest=(char)*iter;
++dest;
}
else if(*iter <= 0x07FF)
{
*dest = (char)(
0xC0 |
((*iter & 0x07C0) >> 6)
);
++dest;

*dest = (char)(
0x80 |
(*iter & 0x003F)
);
++dest;
}
else if(*iter <= 0xFFFF)
{
*dest = (char)(
0xE0 |
((*iter & 0xF000) >> 12)
);
++dest;

*dest = (char)(
0x80 |
((*iter & 0x0FC0) >> 6)
);
++dest;

*dest = (char)(
0x80 |
(*iter & 0x003F)
);
++dest;
}
}

template<typename InputIterator, typename OutputIterator>
OutputIterator wchar_utf8(InputIterator first, InputIterator last, OutputIterator dest)
{
for(; first!=last; ++first)
encode_wchar(first, dest);
return dest;
}

template<typename InputIterator>
wchar_t decode_utf8(InputIterator &iter, InputIterator last)
{
wchar_t ret;

if (((*iter) & 0x80) == 0) // one byte
{
ret = *iter++;
}
else if (((*iter) & 0xe0) == 0xc0) // two bytes
{
wchar_t byte1 = (*iter++) & 0x1f;
wchar_t byte2 = decode_utf8_mb(iter, last);
ret = (byte1 << 6) | byte2;
}
else if (((*iter) & 0xf0) == 0xe0) // three bytes
{
wchar_t byte1 = (*iter++) & 0x0f;
wchar_t byte2 = decode_utf8_mb(iter, last);
wchar_t byte3 = decode_utf8_mb(iter, last);
ret = (byte1 << 12) | (byte2 << 6) | byte3;
}
// TODO: support surrogate pairs
else throw std::runtime_error("UTF-8 not convertable to UTF-16");

return ret;
}

template<typename InputIterator, typename OutputIterator>
OutputIterator utf8_wchar(InputIterator first, InputIterator last, OutputIterator dest)
{
for(; first!=last; ++dest)
*dest = decode_utf8(first, last);
return dest;
}

wap21 2008-12-20
  • 打赏
  • 举报
回复
帮顶
cqsxdb 2008-12-20
  • 打赏
  • 举报
回复
mark
wap21 2008-12-20
  • 打赏
  • 举报
回复
mark
引力场变动源 2008-12-19
  • 打赏
  • 举报
回复
直接使用UTF-8就可以了。
UTF-8也是Unicode的一种,平时说的Unicode其实是UTF-16.UTF-8和UTF-16是Unicode的两种不同的表现形式。使用UTF-8或者UTF-16都是可以在不同语言的OS上显示的,如果不能显示就是字体的问题,更换一个支持Unicode的字体就可以了。

另外,有条件的话,还是使用Unicode(UTF-16)比较好,因为现在OS的核心都是UTF-16的,使用UTF-8或者别的编码的话,OS内部会转换为UTF-16,多少影响一些性能。好像VS2005/2008新建的工程默认也是Unicode(UTF-16)的。
fjfzb 2008-12-19
  • 打赏
  • 举报
回复
有什么办法可以让多字符的字符串在各类语言的OS下都正常显示,这是个聊天的功能,客户端有可能是不同语言环境下的。服务器我用UTF8的方式广播给各客户端,要在各客户端能正常显示聊天内容,人物名称。只需要对人物名称,聊天内容作修改,如果用UNICODE来处理,修改的东西太过庞大,有什么方法能让修改的东西又不多,又能正常显示聊天内容,人物名称。希望从服务器接收到的UTF8字符串后,通过什么转换方式能让它正常显示(不能转成UNICODE),
fjfzb 2008-12-19
  • 打赏
  • 举报
回复
问题是,用多字符在输出,在不同的操作系统显示应该也不正常吧。比如:

wstring str=L"中国共产主义青年团";
printf("字符串的内容为%s.\n",UnicodeToMultiByte(str).c_str());

在简体中文的OS下显示可能正常,但到繁体中文,英文等其它语言的OS下显示就不正常了。

现在我希望无论在什么语言环境下的OS中都能正常显示,
加载更多回复(16)

8,303

社区成员

发帖
与我相关
我的任务
社区描述
游戏开发相关内容讨论专区
社区管理员
  • 游戏开发
  • 呆呆敲代码的小Y
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧