zoukankan      html  css  js  c++  java
  • 关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)

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

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

    image

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

    image

    文件中只有乱码与ASCII码

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

    image

        其中,头两个字节“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!
    ");
            system("pause");
            exit(1);
        }
        //打开、新建存储处理后数据的文件
        if((fp=fopen("BadCodeH.txt","w+"))==NULL)
        {
            printf("Open/Create Destination File Failed!
    ");
            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;
    }

    运行结果如下:

    image

    更一般的情况(文件中有正常的中文字符,乱码和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!
    ");
            system("pause");
            exit(1);
        }
        //打开、新建存储处理后数据的文件
        if((fp=fopen("BadCodeH.txt","w+"))==NULL)
        {
            printf("Open/Create Destination File Failed!
    ");
            system("pause");
            exit(1);
        }
    
        unsigned mapValue[65536];
        if(!ReadMap(mapValue))
        {
            printf("Convert Failed!
    ");
            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;
    }

    例子如下:

    image

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

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

  • 相关阅读:
    iOS中网络请求判断是否设置代理
    swif开发笔记12-Animations
    swift开发笔记11
    swift开发笔记06
    Idea热部署jrebel失败
    Oracle连接知识
    Idea安装及其简介
    博客园cnblog发布word
    en笔记音标
    测试案例小问题
  • 原文地址:https://www.cnblogs.com/xyb930826/p/4657462.html
Copyright © 2011-2022 走看看