小心Windows7的UTF-8代码页
来源:互联网 发布:2017淘宝考试答案50题 编辑:程序博客网 时间:2024/05/17 21:49
目录
第1章小心Windows7的UTF-8代码页 1
1.1 UTF-16与UTF-8相互转换 1
1.1.1 使用Windows API 1
1.1.2 自己编码 1
1.2 测试代码 4
1.3 测试结果 5
第1章小心Windows7的UTF-8代码页
1.1 UTF-16与UTF-8相互转换
发现Windows7的UTF-8代码页有问题的根源就在于UTF-16与UTF-8的相互转换。
1.1.1 使用Windows API
使用Windows API,可以实现UTF-16编码与UTF-8编码的相互转换,如下面的代码:
char a1[128];
wchar_t w = 0;
int n1 = 0;
wchar_t w1[128];
int m1 = 0;
n1 = WideCharToMultiByte(CP_UTF8,0,&w,1,a1,128,NULL,NULL);
m1 = MultiByteToWideChar(CP_UTF8,0,a1,n1,w1,128);
WideCharToMultiByte把UTF-16编码转换为UTF-8编码;
MultiByteToWideChar把UTF-8编码转换为UTF-16编码。
API函数WideCharToMultiByte和MultiByteToWideChar能够正常工作的前提是:Windows系统已经安装了UTF-8代码页。Windows XP、Windows 7默认已经安装了UTF-8代码页,因此不用太担心。Windows Mobile系统就有些麻烦了:有些Windows Mobile安装了UTF-8代码页,而有些没有。所以,为了程序在所有Mobile设备上正常运行,是不能使用WideCharToMultiByte和MultiByteToWideChar的。
1.1.2 自己编码
UTF-16与UTF-8的相互转换,不能使用WideCharToMultiByte和MultiByteToWideChar,怎么办?所幸的是:UTF-16与UTF-8的相互转换是有严格的转换关系的。本文不做这方面的论述,直接上VC++代码:
/*******************************************************************\
将 UTF16 字符串转换为 UTF8 字符串
pUTF16 [in] UTF16 字符串首地址
nLen16 [in] UTF16 字符串字符数,小于 0 表示以 \0 结尾
pUTF8 [out] UTF8 字符串首地址,可以为 NULL
返回:转换的 UTF8 字符个数
\*******************************************************************/
long UTF16to8(const wchar_t*pUTF16,long nLen16,char*pUTF8)
{
long nLen8 = 0;
if(pUTF16)
{
if(nLen16 < 0)
{
nLen16 = wcslen(pUTF16) + 1;
}
}
else
{
nLen16 = 0;
}
if(nLen16 > 0)
{
long i = 0;
wchar_t u = 0;
for(i = 0;i < nLen16;++i)
{
u = pUTF16[i];
if(u <= 0x7F)
{
if(pUTF8)
{
*pUTF8++ = (char)u;
}
++nLen8;
}
else if(u <= 0x7FF)
{
if(pUTF8)
{//110xxxxx 10xxxxxx
pUTF8[1] = (char)(u & 0x3F | 0x80); u >>= 6;
pUTF8[0] = (char)(u & 0x1F | 0xC0);
pUTF8 += 2;
}
nLen8 += 2;
}
else
{
if(pUTF8)
{//1110xxxx 10xxxxxx 10xxxxxx
pUTF8[2] = (char)(u & 0x3F | 0x80); u >>= 6;
pUTF8[1] = (char)(u & 0x3F | 0x80); u >>= 6;
pUTF8[0] = (char)(u & 0x0F | 0xE0);
pUTF8 += 3;
}
nLen8 += 3;
}
}
}
return nLen8;
}
/*******************************************************************\
将 UTF8 字符串转换为 UTF16 字符串
pUTF8 [in] UTF8 字符串首地址
nLen8 [in] UTF8 字符串字符数,小于 0 表示以 \0 结尾
pUTF16 [out] UTF16 字符串首地址,可以为 NULL
返回:转换的 UTF16 字符个数
\*******************************************************************/
long UTF8to16(const char*pUTF8,long nLen8,wchar_t*pUTF16)
{
long nLen16 = 0;
if(pUTF8)
{
if(nLen8 < 0)
{
nLen8 = strlen(pUTF8) + 1;
}
}
else
{
nLen8 = 0;
}
if(nLen8 > 0)
{
long i = 0;
unsigned char u = 0;
for(i = 0;i < nLen8;)
{
u = pUTF8[i];
if(u >= 0xE0)
{
if(pUTF16)
{
*pUTF16++ = (pUTF8[i] & 0x0f) << 12
| (pUTF8[i + 1] & 0x3f) << 6
| (pUTF8[i + 2] & 0x3f);
}
i += 3;
}
else if(u >= 0xC0)
{
if(pUTF16)
{
*pUTF16++ = (pUTF8[i] & 0x1f) << 6
| (pUTF8[i + 1] & 0x3f);
}
i += 2;
}
else
{
if(pUTF16)
{
*pUTF16++ = u;
}
++i;
}
++nLen16;
}
}
return nLen16;
}
1.2 测试代码
自己编写的代码在使用前,那是要测试的。下面就是测试代码。其实就是与WideCharToMultiByte和MultiByteToWideChar进行比较:
void Test()
{
char a1[128];
char a2[128];
wchar_t w;
int n1 = 0;
int n2 = 0;
wchar_t w1[128];
wchar_t w2[128];
int m1 = 0;
int m2 = 0;
for(long i = 0;i <= 0xFFFF;++i)
{
w = (wchar_t)i;
n1 = WideCharToMultiByte(CP_UTF8,0,&w,1,a1,128,NULL,NULL);
m1 = MultiByteToWideChar(CP_UTF8,0,a1,n1,w1,128);
if(m1 != 1 && w1[0] != w)
{//WideCharToMultiByte与MultiByteToWideChar相互转换有问题
TRACE(_T("WideCharToMultiByte,MultiByteToWideChar=%04X\n"),w);
}
n2 = UTF16to8(&w,1,a2);
m2 = UTF8to16(a2,n2,w2);
if(m2 != 1 && w2[0] != w)
{//UTF16to8与UTF8to16相互转换有问题
TRACE(_T("UTF16to8,UTF8to16=%04X\n"),w);
}
if(n1 != n2 || memcmp(a1,a2,n1))
{//UTF16to8与WideCharToMultiByte有出入
TRACE(_T("WideCharToMultiByte,UTF16to8=%04X\n"),w);
}
}
}
1.3 测试结果
测试结果是:
1、在Windows XP下一切正常;
2、在Windows 7(64位旗舰版)下出问题了:当w在0xD800~0xD98A之间时,UTF16to8与WideCharToMultiByte的转换结果不一致!
笔者相信自己的代码,同时又有Windows XP的证明,最终得出的结论就是:Windows7的UTF-8代码页有问题!
还好,0xD800~0xD98A的395个字符并不是很常用,否则Windows7保存的UTF-8文件到了Windows XP或Linux下显示出乱码,问题就严重了。
解决方案:UTF-16与UTF-8编码的相互转换,还是自己编码实现吧。
- 小心Windows7的UTF-8代码页
- 用Windows7玩游戏?小心你的存档!
- 提前用windows7惨重的代价啊,大家小心
- mysql5.7 windows7编码统一utf-8
- 读取UTF-8文件的JAVA代码
- ASP生成UTF-8编码的代码
- 小心那些不具移植性的代码
- 小心!你的代码里有NullPointerException!
- windows7设置MySQL数据库编码为UTF-8
- ASP中将汉字转换为UTF-8的一段代码
- UTF-8与UNICODE的关系及代码转换
- UTF-8与UNICODE的关系及代码转换
- php文件代码采用UTF-8编码的BOM问题
- 中文转换成UTF-8格式的java代码
- UTF-8编码文件去掉BOM的PHP代码
- UTF-8与UNICODE的关系及代码转换
- 修改代码的编码格式为UTF-8
- vs2008设置代码文件的编码为UTF-8
- JQuery重写ajax
- java中JVM的原理
- Android之Observer和Observable
- JNI项目提示“Unresolved inclusion: <jni.h>”的解决方案
- 【SVM/SVR】(1)Libsvm的使用概览
- 小心Windows7的UTF-8代码页
- java 使用 DecimalFormat 保留小数
- 生产者消费者模式
- C++中类定义时不允许使用不完整的类型错误提示原因分析
- 保留小数:java DecimalFormat format 方法的使用
- Serializable 和 Parcelable 区别
- 图解正向代理、反向代理
- SpringMVC
- 利用AWS免费EC2搭建加密代理