zoukankan      html  css  js  c++  java
  • 小心Windows7的UTF-8代码页

    1小心Windows7UTF-8代码页    1

    1.1 UTF-16UTF-8相互转换    1

    1.1.1 使用Windows API    1

    1.1.2 自己编码    1

    1.2 测试代码    4

    1.3 测试结果    5

    1小心Windows7UTF-8代码页

    1.1 UTF-16UTF-8相互转换

    发现Windows7UTF-8代码页有问题的根源就在于UTF-16UTF-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);

    WideCharToMultiByteUTF-16编码转换为UTF-8编码;

    MultiByteToWideCharUTF-8编码转换为UTF-16编码。

    API函数WideCharToMultiByteMultiByteToWideChar能够正常工作的前提是:Windows系统已经安装了UTF-8代码页。Windows XPWindows 7默认已经安装了UTF-8代码页,因此不用太担心。Windows Mobile系统就有些麻烦了:有些Windows Mobile安装了UTF-8代码页,而有些没有。所以,为了程序在所有Mobile设备上正常运行,是不能使用WideCharToMultiByteMultiByteToWideChar的。

    1.1.2 自己编码

    UTF-16UTF-8的相互转换,不能使用WideCharToMultiByteMultiByteToWideChar,怎么办?所幸的是:UTF-16UTF-8的相互转换是有严格的转换关系的。本文不做这方面的论述,直接上VC++代码:

    /*******************************************************************

    UTF16 字符串转换为 UTF8 字符串

    pUTF16 [in] UTF16 字符串首地址

    nLen16 [in] UTF16 字符串字符数,小于 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 表示以 结尾

    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 测试代码

    自己编写的代码在使用前,那是要测试的。下面就是测试代码。其实就是与WideCharToMultiByteMultiByteToWideChar进行比较:

    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)

    {//WideCharToMultiByteMultiByteToWideChar相互转换有问题

    TRACE(_T("WideCharToMultiByte,MultiByteToWideChar=%04X "),w);

    }

    n2 = UTF16to8(&w,1,a2);

    m2 = UTF8to16(a2,n2,w2);

    if(m2 != 1 && w2[0] != w)

    {//UTF16to8UTF8to16相互转换有问题

    TRACE(_T("UTF16to8,UTF8to16=%04X "),w);

    }

    if(n1 != n2 || memcmp(a1,a2,n1))

    {//UTF16to8WideCharToMultiByte有出入

    TRACE(_T("WideCharToMultiByte,UTF16to8=%04X "),w);

    }

    }

    }

    1.3 测试结果

    测试结果是:

    1、在Windows XP下一切正常;

    2、在Windows 764位旗舰版)下出问题了:当w0xD800~0xD98A之间时,UTF16to8WideCharToMultiByte的转换结果不一致!

    笔者相信自己的代码,同时又有Windows XP的证明,最终得出的结论就是:Windows7UTF-8代码页有问题!

    还好,0xD800~0xD98A395个字符并不是很常用,否则Windows7保存的UTF-8文件到了Windows XPLinux下显示出乱码,问题就严重了。

    解决方案:UTF-16UTF-8编码的相互转换,还是自己编码实现吧。

  • 相关阅读:
    java中栈内存和堆内存的简单理解
    java中构造函数与一般函数的区别

    另一部漫画
    海边的卡夫卡
    11-12
    这篇大概值一百万吧
    我的千岁寒
    11-9
    嗯……………股票已经涨的我不想上班了
  • 原文地址:https://www.cnblogs.com/hanford/p/6177935.html
Copyright © 2011-2022 走看看