• Ansi,UTF8,Unicode编码(续)


    1.三种编码的回顾

    Ansi字符串我们最熟悉,英文占一个字节,汉字2个字节,以一个\0结尾,常用于txt文本文件。
    Unicode字符串,每个字符(汉字、英文字母)都占2个字节;在VC++的世界里,Microsoft比较鼓励使用Unicode,如wchar_t。
    UTF8是Unicode一种压缩形式,英文A在unicode中表示为0x0041,英语中这种存储方式太浪费,因为浪费了50%的空间,于是就把英文压缩成1个字节,成了utf8编码;但是汉字在utf8中占3个字节,显然用做中文不如ansi合算,这就是中国的网页用作ansi编码而国外的网页常用utf8的原因。程序中把15.7M大小UTF8格式的txt文件转化为ANSI后,大小仅为10.8M。

    2.转换函数

    一般情况下,可以通过Windows头文件下的两个函数实现各个类型之间的转换。头文件添加:

    #include <Windows.h>

    多字节字符集 -> Unicode字符集

    int MultiByteToWideChar(
      __in   UINT CodePage, // 标识了与多字节关联的一个代码页值
      __in   DWORD dwFlags, // 允许我们进行额外的控制,它会影响带变音符号(比如重音)的字符。但是一般情况下不适用,赋为 0 即可。
      __in   LPCSTR lpMultiByteStr, // 参数指定要转换的字符串
      __in   int cbMultiByte, // 指定要转换串长度的长度(字节数),如果参数值是-1,函数便可自动判断源字符串的长度
      __out  LPWSTR lpWideCharStr, // 指定转换后Unicode版本的字符串内存地址
      __in   int cchWideChar        // 指定 lpWideCharStr 缓冲区的最大长度。
                                    // 如果传入0,函数不会进行转换,而是返回一个宽字符数(包括终止字符'\0'),
                    // 只有当缓冲区能够容纳该数量的宽字符时,转换才会成功。
    );

    Unicode字符集 –> 多字节字符集

    int WideCharToMultiByte(
      __in   UINT CodePage,   // 标志了要与新转换的字符串关联的代码页
      __in   DWORD dwFlags,   // 制定额外的转换控制,一般不需要进行这种程度的控制,而为 dwFlag 传入 0
      __in   LPCWSTR lpWideCharStr, // 指定要转换的字符串的内存地址
      __in   int cchWideChar,       // 指出该字符串的长度,如果传入 -1 ,则由函数来判断字符串的长度
      __out  LPSTR lpMultiByteStr,  // 转换后的缓冲区
      __in   int cbMultiByte,       // 指定 lpMultiByteStr 缓冲区的最大大小(字节数),如果传入 0 ,函数返回该目标缓冲区需要的大小
      __in   LPCSTR lpDefaultChar,  
      __out  LPBOOL lpUsedDefaultChar // 宽字符字符串中,如果至少有一个字符不能转换为对应的多字节形式,函数就会把这个变量设为 TRUE 。如果所有字符都能成功转换,就会把这个变量设为 FALSE。 通常将此函数传入 NULL 值。
    );

    只有一个字符在 CodePage 制定的代码页中没有对应的表示时,WideCharToMultiByte 才会使用后两个参数。在遇到一个不能转换的字符时,函数便使用 lpDefaultChar 参数指向的字符。如果这个参数指向为 NULL ,函数就会使用一个默认的字符。这个默认的值通常是一个问号。这对文件操作是非常危险的,因为问号是一个通配符。

    3.程序实现

    程序的头文件:

    /*
     *作者:侯凯
     *说明:utf8、unicode、utf8相互转化
     *日期:2013-6-4
    */
    #include <iostream>
    #include <string>
    #include <fstream>
    #include <Windows.h> //Windows头文件
    using std::string;
    using namespace std;

    ANSI转Unicode

    void AnsiToUnicode() 
    {
        char* sAnsi = "ANSI to Unicode, ANSI 转换到 Unicode";
    
        //ansi to unicode
        int sLen = MultiByteToWideChar(CP_ACP, NULL, sAnsi, -1, NULL, 0); 
        wchar_t* sUnicode = new wchar_t[sLen];
        //wchar_t* sUnicode = (wchar_t*)malloc(sLen*sizeof(wchar_t));
        MultiByteToWideChar(CP_ACP, NULL, sAnsi, -1, sUnicode, sLen); 
    
        ofstream rtxt("ansitouni.txt");
        rtxt.write("\xff\xfe",2);//原因参见上一篇——"小尾"字节序方式存储
        rtxt.write((char*)sUnicode, sLen*sizeof(wchar_t));
        rtxt.close();
    
        delete[] sUnicode; 
        sUnicode =NULL; 
        //free(sUnicode);
    }

    Unicode转ANSI

    void UnicodeToAnsi() 
    {
        wchar_t *sUnicode = L"Convert Unicode to ANSI, Unicode 转换为 ANSI";
    
        //unicode to ansi
        int sLen = WideCharToMultiByte(CP_ACP, NULL, sUnicode, -1, NULL, 0, NULL, NULL); 
        char* sAnsi = new char[sLen];
        //char* sAnsi = (char*)malloc(sLen);
        WideCharToMultiByte(CP_ACP, NULL, sUnicode, -1, sAnsi, sLen, NULL, NULL); 
    
        ofstream rtxt("unitoansi.txt");
        rtxt.write(sAnsi, sLen);
        rtxt.close();
    
        delete[] sAnsi; 
        sAnsi =NULL; 
        //free(sAnsi);
    }

    Unicode转UTF8

    void UnicodeToUtf8()
    {
        wchar_t *sUnicode = L"Convert Unicode to UTF8, Unicode 转换为 UTF8"; 
        // unicode to UTF8 
        int sLen = WideCharToMultiByte(CP_UTF8, NULL, sUnicode, -1, NULL, 0, NULL, NULL); 
        //UTF8虽然是Unicode的压缩形式,但也是多字节字符串,所以可以以char的形式保存 
        char* sUtf8 = new char[sLen];  
        //unicode版对应的strlen是wcslen 
        WideCharToMultiByte(CP_UTF8, NULL, sUnicode, -1, sUtf8, sLen, NULL, NULL); 
    
        ofstream rtxt("unitoutf8.txt");
        rtxt.write("\xef\xbb\xbf", 3);//原因参见上一篇
        rtxt.write(sUtf8, sLen);
        rtxt.close();
    
        delete[] sUtf8; 
        sUtf8 =NULL; 
    }

    UTF8转Unicode

    void Utf8ToUnicode()
    {    
        //UTF8 Convert to Unicode, UTF8 转换为 Unicode,用UE十六进制打开“转化为”直接复制过来乱码,用16进制表示
        char* sUtf8 = "UTF8 Convert to Unicode, UTF8 \xe8\xbd\xac\xe6\x8d\xa2\xe4\xb8\xba Unicode"; 
        //UTF8 to Unicode 
        int sLen = MultiByteToWideChar(CP_UTF8, NULL, sUtf8, -1, NULL, 0); 
        wchar_t* sUnicode = new wchar_t[sLen]; 
        MultiByteToWideChar(CP_UTF8, NULL, sUtf8, -1, sUnicode, sLen);
    
        ofstream rtxt("utf8touni.txt");
        rtxt.write("\xff\xfe",2);
        rtxt.write((char*)sUnicode, sLen*sizeof(wchar_t));
        rtxt.close();
    
        delete[] sUnicode; 
        sUnicode =NULL;  
    }

    Ansi转换utf8和utf8转换Ansi就是上面2个的结合,把unicode作为中间量,进行2次转换即可。

    4.UTF8转ANSI

    在网络传输中,我们常常使用UTF8编码,但在程序处理时,我们习惯于ANSI编码,至少目前的VS2010对UTF8码的显示是乱码的。以下函数综合上述程序,实现了txt文件UTF8编码向ANSI编码的转化。

    //changeTxtEncoding修改字符串的编码  
    
    char* changeTxtEncoding(char* szU8)
    {  
        int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szU8, -1, NULL, 0);  
        wchar_t* wszString = new wchar_t[wcsLen];
        ::MultiByteToWideChar(CP_UTF8, NULL, szU8, -1, wszString, wcsLen);
        cout<<wszString<<endl;
    
        int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString, -1, NULL, 0, NULL, NULL);  //wcslen(wszString)
        char* szAnsi = new char[ansiLen];  
        ::WideCharToMultiByte(CP_ACP, NULL, wszString, -1, szAnsi, ansiLen, NULL, NULL); 
        delete[] wszString;
        return szAnsi;  
    }
    
    void changeTextFromUtf8ToAnsi(const char* filename)  
    {  
        ifstream infile;
        string strLine="";
        string strResult="";  
        infile.open(filename);
        infile.seekg(3, ios::beg);
        if (infile)  
        {  
            while(!infile.eof())
            {  
                getline(infile,strLine);  
                strResult+=strLine+"\n";
            }  
        }
        infile.close();
        char* changeTemp=new char[strResult.length()+1];
        changeTemp[strResult.length()]='\0'; //问题记录
        strcpy(changeTemp, strResult.c_str()); //const char*转化char*的方法
        char* changeResult=changeTxtEncoding(changeTemp); 
        strResult=changeResult;  
    
        ofstream outfile;  
        outfile.open("ANSI.txt");  
        outfile.write(strResult.c_str(), strResult.length());  
        outfile.flush();  
        outfile.close();
        delete[] changeResult;
        delete[] changeTemp;
    }

    问题记录:
    关于字符串的长度a.String类型的length()和size()函数都返回字符串的真实大小,不包括'\0‘ ;
    b.char*类型的strlen()函数也是返回字符串的真实大小,不包括'\0‘ ;
    c.注意,sizeof()函数包含'\0‘ ,如char str[] = “Hello” ;则sizeof (str ) = 6。

  • 相关阅读:
    hdu 1174
    计算几何模板
    又是一年博客记
    hdu 1225 Football Score
    与逆序数有关的
    hdu 2844 Coins
    hdu 1171 Big Event in HDU
    UVA Exponentiation
    UVA Summation of Four Primes
    Linux:设置alias永久生效
  • 原文地址:https://www.cnblogs.com/houkai/p/3117801.html
Copyright © 2020-2023  润新知