码迷,mamicode.com
首页 > 其他好文 > 详细

关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)

时间:2015-07-18 21:17:51      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

    在上篇日志中(链接),我们讨论了utf-8编码和GBK编码之间转化的乱码问题,这一篇我们讨论Unicode(utf-16编码方式)与GBK编码之间转换的乱码问题。

    在Windows系统自带的记事本中,我们按照图中所示使用Unicode编码保存。

技术分享

    在Visual Studio 2005中,单击“文件|高级保存选项”中选择Unicode-代码页1200。

技术分享

文件中只有乱码与ASCII码

    按照上一篇日志中的方法,我们使用WinHex软件查看文件的16进制数据,如下:

技术分享

    其中,头两个字节“FF FE”代表utf-16的BOM码,从D4开始就是数据,即:

0xd4    0x00    0xda    0x00    
0xb4    0x00    0xcb    0x00    
0xcc    0x00    0xed    0x00    
0xbc    0x00    0xd3    0x00    
0xd7    0x00    0xa8    0x00    
0xd3    0x00    0xc3    0x00    
0xb4    0x00    0xfa    0x00    
0xc2    0x00    0xeb    0x00    
0xba    0x00    0xcd    0x00    
0x2f    0x00    
0xbb    0x00    0xf2    0x00    
0xb5    0x00    0xf7    0x00    
0xd3    0x00    0xc3    0x00    
0xbb    0x00    0xf9    0x00    
0xc0    0x00    0xe0    0x00

    我们同时找出正确字符的GBK编码值

0xd4    0xda    
0xb4    0xcb    
0xcc    0xed    
0xbc    0xd3    
0xd7    0xa8    
0xd3    0xc3    
0xb4    0xfa    
0xc2    0xeb    
0xba    0xcd    
0x2f    
0xbb    0xf2    
0xb5    0xf7    
0xd3    0xc3    
0xbb    0xf9    
0xc0    0xe0

    我们很容易发现,只要将偶数列中的0x00数消除就可以了,当然,我们格式也从utf-8变为GBK了。

    对应的C语言程序如下:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    FILE* fp;
    FILE* fp2;
    //打开存储乱码的文件,utf-16编码格式,二进制打开
    if((fp2=fopen("BadCode.txt","rb+"))==NULL)
    {
        printf("Open Source File Failed!\n");
        system("pause");
        exit(1);
    }
    //打开、新建存储处理后数据的文件
    if((fp=fopen("BadCodeH.txt","w+"))==NULL)
    {
        printf("Open/Create Destination File Failed!\n");
        system("pause");
        exit(1);
    }

    //乱码第一个高位字节
    unsigned ch;
    //乱码第一个低位字节
    unsigned cl;
    //乱码第二个高位字节
    unsigned ch2;
    //乱码第二个低位字节
    unsigned cl2;

    ch=fgetc(fp2);
    //丢弃BOM字节信息
    if(ch==0xff)
    {
        fgetc(fp2);
        ch=fgetc(fp2);
    }

    cl=fgetc(fp2);
    while(!feof(fp2))
    {
        //乱码,接着读取两个字节,再丢弃偶数字节
        if (ch>0x7f && cl==0x00)
        {
            ch2=fgetc(fp2);
            cl2=fgetc(fp2);
            fputc(ch,fp);
            fputc(ch2,fp);
        }
        //ASCII码,丢弃偶数字节
        else
        {
            fputc(ch,fp);
            
        }
        ch=fgetc(fp2);
        cl=fgetc(fp2);
    }
    fclose(fp);
    fclose(fp2);
    system("pause");
    return 0;
}

运行结果如下:

技术分享

更一般的情况(文件中有正常的中文字符,乱码和ASCII字符)

    和上一篇日志中分析的差不多,对于正常的utf-16编码的字符,我们只要将其转换为GBK编码输出就可以了,需要注意的是,正常的utf-16字符编码在文件中的存储方式:高位字节存放编码的后两位,低位字节存放编码的前两位。

C语言程序如下,戳此处下载UnicodeToGBK.txt文件:

#include <stdio.h>
#include <stdlib.h>

//读取utf-16和GBK转换表中的数据
bool ReadMap(unsigned* mapValue)
{
    //声明文件指针
    FILE* fp;
    
    //以可读写方式打开映射数据的文本文件
    if (NULL == (fp = fopen("UnicodeToGBK.txt", "r+")))
    {
        printf("Error!");
        system("pause");
        return false;
    }
    

    //存储Unicode的16进制数据的字符串
    char utfStr[4];
    //存储gbk的16进制数据的字符串
    char gbkStr[4];
    //存储Unicode16进制数据
    unsigned utfId;
    //存储gbk的16进制数据
    unsigned gbkId;
    //处理字符的临时变量
    char c;
    //读取数据

    while(!feof(fp))
    {
        //读Unicode值的字符串
        fread(utfStr,4,1,fp);
        //转换为整型
        sscanf(utfStr,"%4x",&utfId);
        fgetc(fp);
        //读gbk值的字符串
        fread(gbkStr,4,1,fp);
        //转化为整型
        sscanf(gbkStr,"%4x",&gbkId);
        fgetc(fp);

        //赋值
        mapValue[utfId]=gbkId;    
    }
    

    fclose(fp);
    return true;
}

int main(int argc, char const *argv[])
{
    FILE* fp;
    FILE* fp2;
    //打开存储乱码的文件,utf-16编码格式,二进制打开
    if((fp2=fopen("BadCode.txt","rb+"))==NULL)
    {
        printf("Open Source File Failed!\n");
        system("pause");
        exit(1);
    }
    //打开、新建存储处理后数据的文件
    if((fp=fopen("BadCodeH.txt","w+"))==NULL)
    {
        printf("Open/Create Destination File Failed!\n");
        system("pause");
        exit(1);
    }

    unsigned mapValue[65536];
    if(!ReadMap(mapValue))
    {
        printf("Convert Failed!\n");
        system("pause");
        exit(1);
    }
    //乱码第一个高位字节
    unsigned ch;
    //乱码第一个低位字节
    unsigned cl;
    //乱码第二个高位字节
    unsigned ch2;
    //乱码第二个低位字节
    unsigned cl2;
    //存储utf-16编码的值
    unsigned utf;
    //存储gbk编码的值
    unsigned gbk;

    ch=fgetc(fp2);
    //丢弃BOM字节信息
    if(ch==0xff)
    {
        fgetc(fp2);
        ch=fgetc(fp2);
    }

    cl=fgetc(fp2);
    while(!feof(fp2))
    {
        //乱码,接着读取两个字节,再丢弃偶数字节
        if (ch>0x7f && cl==0x00)
        {
            ch2=fgetc(fp2);
            cl2=fgetc(fp2);
            fputc(ch,fp);
            fputc(ch2,fp);
        }
        //ASCII码,丢弃偶数字节
        else if(ch<=0x7f && cl==0x00)
        {
            fputc(ch,fp);
            
        }
        //否则就是正常字符,进行编码转换后输出
        else
        {
            
            utf=cl*256+ch;
            gbk=mapValue[utf];            
            fputc(gbk/256,fp);
            fputc(gbk%256,fp);
        }
        ch=fgetc(fp2);
        cl=fgetc(fp2);
    }
    fclose(fp);
    fclose(fp2);
    system("pause");
    return 0;
}

例子如下:

技术分享

    未来我会将两篇文章中的程序进行整合,写一个图形界面的程序出来。

    若有错误,恳请各位大侠指教~~

关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)

标签:

原文地址:http://www.cnblogs.com/xyb930826/p/4657462.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!