ASCII Unicode, UTF8 的关系,string和wstring转换

  写这篇文章遇到的的问题是c++操作正则的时候,遇到中文出现匹配失败。以及visual studio中中文乱码问题。当时这里卡住了项目进程,最后花费很多时间才解决。主要问题是中文编码编码问题。特记录分享,避免踩坑。

1. 三大编码由来和转换

  计算机中所有数据存储都是01两个量表示,但是如何将01转换为我们日常使用的字符,这就依赖编码。众所周知,最早的计算机是美国人发明的,所以计算机最早表达的语言肯定是英文。英文字母只有26个。所以提出了单字节编码ASCII编码。用来解决字符在计算机中的存储表示问题。如大写的字符A编码为65(二进制01000001)一个字节就可以存储。

 ASCII : 使用指定的 7 位或 8 位二进制数(单字节)组合来表示 128 或 256 种可能的字符。标准 ASCII 码也叫基础ASCII码,使用 7 位二进制数来表示所有的大写和小写字母,数字 0 到 9、标点符号, 以及在美式英语中使用的特殊控制字符。

  其他国家,比如汉语也有字符编码的需求。但是ASCII采用单字节,表示的字符有限,无法满足其他语言编码的拓展。于是推出了多字节编码的Unicode编码来满足大多数国家的文字的编码。如:字符‘A’的编码为00000000 01000001,就是在ASCII中在高位加8个0。

Unicode:采用的是两个字节(16位二进制)来表示字符,这样能基本满足各种国家语言字符的需求。

  虽然Unicode编码解决了世界文字编码大一统的问题,但Unicode只规定了符号的二进制编码,而并没有规定这个而二进制编码如何存储。通常一个中文字符需要两个字节来存储,特殊的字符可能需要三个四个字节存储。计算机无法知道几个字节表示一个字符,也就无法识别unicode码。如果规定每个unicode码用固定的多个字节来保存,那英文字符前面需要添加多个0,这是对存储是极大的浪费。在解决内存空间这件事上,从来难不倒抠门的码农。于是设计出了UTF8编码。

UTF-8: 是一种针对Unicode的可变长度的字符编码方式。它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码。

  UTF8编码是一种变长的编码方式。其使用1-4字节来表示一个符号 。UTF8编码方式很简单,只有两个规则:

 >1.  对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。 
以A为例:
ASCII: 01000001 --> Unicode: 00000000 01000001 --> UTF8: 01000001
  1. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
以‘中’(4E2D)字为例:4E2D 在在第三行的范围内(0000 0800 - 0000 FFFF)所以‘中’编码需要三个字节。即格式是1110 xxxx 10xx xxxx 10xx xxxx。从最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。
UTF8: 100 1110 0010 1101    -> Unicode: 1110 0100 1011 1000 1010 1101

2. 三大编码在计算机中应用:

  1. 在计算机内存磁盘交互场景中:

  在计算机内存中统一使用Unicode编码,进行字符处理,但是数据保存到磁盘文件中,先转换成UTF8以节约空间,然后呢存储。

  内存读取磁盘文件中字符数据,也需要先将UTF8数据转换成Unicode编码,然后保存在内存中供计算机处理。

请添加图片描述

  1. web数据传输:

  服务器中以Unicode编码,来保存数据,但是在向浏览器发送数据时候,会将字符转换成UTF8,发送给浏览器。以缩小通信数据。

请添加图片描述

3. char(string)和wchar_t (wstring)转换

  关于这个问题的讨论起源于正则表达式。在中文匹配的时候,正则表达式无法匹配到中文符号。经过查阅资料发现,正则表达表达式是按照Unicode编码来匹配中文的。但是string中存储的是中文是UTF8编码,而非Unicode编码的字符导致无法匹配。要想正则表达是必须将中文字符集编码转换成Unicode编码。

window:转换

        std::wstring Utf82Unicode(const std::string& utf8){
    
    
            int unicodeLen = MultiByteTowideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr,0);
            wchar_t* pUnicode = (wchar_t*)malloc(sizeof(wchar_t) * unicodeLen);
            MultiByteTowideChar(CP_UTF8, 0, utf8.c_str()-1, pUnicode, unicodeLen);
            std::wstring ret str = pUnicode;
            free(pUnicode);
            return ret str;
        }
        
        std::string Unicode2Utf8(const std::wstring& wstr)
        int ansiilen = WideCharToMultiByte(CP_UTF8, 0, wstr.c str(), -1, nullptr, 0, nullptr, nullptr);
        char* pAscii = (char*)malloc(sizeof(char) * ansiiLen);
        WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiilen, nullptr, nullptr);
        std::string str = pAscii;
        free(pAscii);
        return str;
        
        std::wstring Ascii2Unicode(const std::string& str){
    
    
            int unicodeLen = MultiByteTowideChar(CP ACP, , str.c_str(), -1, nullptr,0);
            wchar_t* pUnicode = (wchar_t*)malloc(sizeof(wchar_t) *unicodeLen);
            MultiByteTowideChar(CP_ACP, 0, str.c_str()-1, pUnicode, unicodeLen);
            std::wstring str = pUnicode;
            free(pUnicode):
            return str;
        }
        
        
        std::string Unicode2Ascii(const std::wstring& wstr){
    
    
            int ansiilen = WidecharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
            char* pAssii = (char*)malloc(sizeof(char) * ansiiLen);
            WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, pAssii, ansiilen, nullptr, nullptr);
            std::string str = pAssii;
        	free(pAssii);
        	return str;
        }
        
        
         // utf8和ascii 无法直接互转可通过unicode 转换实现。
        

linux:转换

        std::wstring Utf82Unicode(const std::string& utf8){
    
    
        	wstring result;
            const char * pUtf8Buff = utf8.c_str();
            // 地域设置信息
        	char* old locale = setlocale(LC_CTYPE,"en_US.UTF8");
            //将多字节字符串转换为宽字符串,确定宽字节长度
            int unicode buff size = mbstowcs(NULL, pUtf8Buff, 0);
            if(0 == unicode buff_size){
    
    
        		return result;
            }
        	unicode_buff_size += 8; // 给更多额外的空间
        	result.resize(unicode_buff_size):
            //将多字节字符串转换为宽字串
            unicode_buff_size = mbstowcs((wchar t*)result.c_str(), putf8Buff, unicode_buff_size + 1):
            setlocale(LC_CTYPE, old_locale);
            return result:
        }
        
        
        std::string Unicode2Utf8(const std::wstring& wstr) {
    
    
            string result;
        	const wchar t * pwBuff = wstr.c_str();//地域设置信息
        	char* old locale = setlocale(LC_CTYPE,"en_US.UTF8");
            int Utf8Buffsize = wcstombs(NULL, pwBuf, 0);
            if( == Utf8Buffsize) {
    
    
                return result;
            }
        	Utf8Buffsize += 8; // 给更多额外的空间result.resize(Utf8Buffsize);
        	Utf8Buffsize = wcstombs((char*)result.c_str(), pwBuff Utf8Buffsize + 1);
            setlocale(LC_CTYPE, old_locale);
            return result:
        }
        
        
        

猜你喜欢

转载自blog.csdn.net/qq_41546984/article/details/131190708