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编码的相互转换,还是自己编码实现吧。

  • 相关阅读:
    LeetCode 81 Search in Rotated Sorted Array II(循环有序数组中的查找问题)
    LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)
    LeetCode 79 Word Search(单词查找)
    LeetCode 78 Subsets (所有子集)
    LeetCode 77 Combinations(排列组合)
    LeetCode 50 Pow(x, n) (实现幂运算)
    LeetCode 49 Group Anagrams(字符串分组)
    LeetCode 48 Rotate Image(2D图像旋转问题)
    LeetCode 47 Permutations II(全排列)
    LeetCode 46 Permutations(全排列问题)
  • 原文地址:https://www.cnblogs.com/hanford/p/6177935.html
Copyright © 2011-2022 走看看