当前位置:   article > 正文

ASCII字符集、Unicode字符集下UTF-8 和UTF-16编码、GBK(GB2312)字符集_utf-16 gbk

utf-16 gbk

什么是字符集

字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、unicode字符集等.

什么是字符编码?

1、 计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。
2、 字符编码(encoding)和字符集不同。字符集只是字符的集合,不一定适合作网络传送、处理,有时须经编码(encode)后才能应用。如Unicode可依不同需要以UTF-8、UTF-16、UTF-32等方式编码。
3、字符编码就是以二进制的数字来对应字符集的字符。 因此,对字符进行编码,是信息交流的技术基础。

注意:Unicode字符集有多种编码方式,如UTF-8、UTF-16等;ASCII只有一种;大多数MBCS(包括GB2312,GBK)也只有一种。
 

ASCII

ASCII码是西欧编码的方式,采取7位编码,所以是2^7=128,共可以表示128个字符,包括34个字符,(如换行LF,回车CR等),其余94位为英文字母和标点符号及运算符号等。

ASCII表

 字符集:从符号(NUL=”/0”=“空操作字符”)到“Z”再到“DEL”符号
字符编码范围:二进制:00000000——01111111 十进制:0-127
占用字节:1字节 

GB2312字符集

GB2312 是对 ASCII 的中文扩展。兼容ASCII。

编码规定:
编码小于127的字符与ASCII编码相同,
特性:两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。

字符集:从符号(NUL=”/0”=“空操作字符”)到“Z”到“齄”(简体中文)
字符编码范围:16进制:0x0000-(中间有一部分是未使用的)-0xF7FE
占用字节:英文 1字节    中文占 2字节
 

GBK

GBK 兼容ASCLL 兼容 GB2312 是GB2312的扩展。  中文 占2字节
但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,不得不继续把 GB2312 没有用到的码位找出来用上。后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 “GBK” 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。

Unicode 是「字符集」

最初的unicode编码是固定长度的,16位,也就是两个字节代表一个字符,这样一共可以表示65536个字符。显然,这样要表示各种语言中所有的字符是远远不够的。Unicode4.0规范考虑到了这种情况,定义了一组附加字符编码,附加字符编码采用2个16位来表示,这样最多可以定义1048576个附加字符,目前unicode4.0只定义了45960个附加字符。

Unicode长度为4字节。

Unicode为世界上所有字符都分配了一个唯一的数字编号,这个编号范围从 0x000000 到 0x10FFFF(十六进制),有110多万,每个字符都有一个唯一的Unicode编号,这个编号一般写成16进制。例如「知」的码位是 30693,记作 U+77E5(30693 的十六进制为 0x77E5)。

它是一种规定,Unicode本身只规定了每个字符的数字编号是多少,并没有规定这个编号如何存储。

Unicode编码体系下需要4个字节,其余3个字节为空。这就导致资源的浪费。

为了解决Unicode带来的资源浪费,采用变长的字节码(如UTF-8)或者定长的字节码表示,可以理解成 压缩Unicode。

 定长字符编码

UCS-2

 UCS-2(Universal Character Set coded in 2 octets),是用定长2个字节来表示字符(定长编码),其取值范围为 U+0000~U+FFFF。 
Unicode当前默认的版本是UCS-2,UCS-2 编码 与 Unicode码 完全一样,6w+的字符量已经足以用于全球的主要语言的大多数字符。
UCS-2的优点:
对于亚洲字符的存储空间需求比UTF-8少,因为每个字符都是2个字节。
处理字符的速度比UTF-8更快,因为是固定长度编码的。
对于windows和java的支持更好。

window和java则支持UCS-2。

UCS-4

即用四个字节表示代码点。它的范围为 U+00000000~U+7FFFFFFF,允许表示一百多万个字符。其中 U+00000000~U+0000FFFF和UCS-2是一样的。

可变长度字符编码

UTF-8

Unicode是一个字符集,而UTF-8是Unicode的其中一种,UTF-8以字节为单位对Unicode进行编码。UTF-8中英文字符占一个字节,汉字占三个字节

其中:  字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point) 

编码规则:将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)

 UTF-8 顾名思义,是一套以 8 位为一个编码单位的可变长编码。会将一个码位编码为 1 到 4 个字节这个变化是根据 Unicode 编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多。

UTF-8使用1~4字节为每个字符编码:

·一个US-ASCIl字符只需1字节编码(Unicode范围由U+0000~U+007F)。

·带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文等字母则需要2字节编码(Unicode范围由U+0080~U+07FF)。

·其他语言的字符(包括中日韩文字、东南亚文字、中东文字等)包含了大部分常用字,使用3字节编码。

·其他极少使用的语言字符使用4字节编码

UTF-8是这样做的:

1. 单字节的字符,字节的第一位设为0,对于英语文本,UTF-8码只占用一个字节,和ASCII码完全相同;

2. n个字节的字符(n>1),第一个字节的前n位设为1,第n+1位设为0,后面字节的前两位都设为10,这n个字节的其余空位填充该字符unicode码,高位用0补足。

Unicode符号范围     |        UTF-8编码方式
(十六进制)        |              (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

因此:是任何字符对应的数字保存时所占的空间是可变的,使用一至四个字节为每个字符编码,其中大部分汉字采用三个字节编码,少量不常用汉字采用四个字节编码.而UTF-8由于里面有额外的标志信息,所有一个字节只能表示2的7次方128个字符,两个字节只能表示2的11次方2048个字符,而三个字节能表示2的16次方,65536个字符。

优点:兼容了 ASCII 码,节约空间,且没有字节顺序的问题。

Unix平台中普遍支持UTF-8字符集。

UTF-16

UTF-16:使用二或四个字节为每个字符编码,其中大部分汉字采用两个字节编码,少量不常用汉字采用四个字节编码。是任何字符对应的数字都用两个字节来保存,但如果都是英文字母(一个字节能表示一个字符)这样做有点浪费。由于UTF-16不需要用其它字符来做标志,所以两字节也就是2的16次能表示65536个字符。

缺点:仍不兼容 ASCII 码(一个英文字母要用2个字节来表示),仍有大小端格式问题。

常见的场景

1.Qt Creator使用的是utf-8来读取文本文件.

qt MSVC编码是windows本地的字符集如GB2312

相当于编译保存是GB2312,运行解码是utf-8.不匹配,导致乱码。

解决办法:qt 使用msvc编译器出现中文乱码的问题_小飞侠hello的博客-CSDN博客_qt msvc编译器中文字符串编译报错及乱码问题

Qt 自带的mingw 一般不会出现乱码问题.

2. vs里面的unicode字符集就是采用的utf-16(用二个字节存储一个字符)或者说是usc-2.

3.QString 内部是以 16 位的 QChar 来存储(Unicode 的一种,但不是 utf-8,即utf-16)

4.8,QString转入转出函数,即生成QString和由QString生成其他字符(如char)的函数
toUtf8是输出UTF-8编码的字符集
Local8bit是本地操作系统设置的字符集编码,一般为GB2312.
 

互换函数

GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:
GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312

具体见:

windows下提供了两个编码转换函数:WideCharToMultiByte和MultiByteToWideChar。
用它们可实现Unicode(UCS2),UTF8,GBK(GB2312)互转。

int
WINAPI
MultiByteToWideChar(
    __in UINT     CodePage,
    __in DWORD    dwFlags,
    __in_bcount(cbMultiByte) LPCSTR   lpMultiByteStr,
    __in int      cbMultiByte,
    __out_ecount_opt(cchWideChar) __transfer(lpMultiByteStr) LPWSTR  lpWideCharStr,
    __in int      cchWideChar);
 
int
WINAPI
WideCharToMultiByte(
    __in UINT     CodePage,
    __in DWORD    dwFlags,
    __in_ecount(cchWideChar) LPCWSTR  lpWideCharStr,
    __in int      cchWideChar,
    __out_bcount_opt(cbMultiByte) __transfer(lpWideCharStr) LPSTR   lpMultiByteStr,
    __in int      cbMultiByte,
    __in_opt LPCSTR   lpDefaultChar,
    __out_opt LPBOOL  lpUsedDefaultChar);

第一个参数,CodePage,通常取两个值:
1、CP_UTF8,将UTF8转换成Unicode的时使用。
2、CP_ACP,Ansi Code Page,也就是计算机本地的代码页,中国大陆为936(简体中文),也就是GetACP()的返回值。Unicode转换成GBK相互转换时使用。

#define CP_ACP                    0           // default to ANSI code page

#define CP_UTF8                   65001       // UTF-8 translation

string 转 wstring 或者说 char * 转 wchar*

这就是为了防止string类型的乱码,需要把string 转换成wstring.

在MFC中,Cstring str = wstring wstr.c_str();

  1. //#define CP_ACP 0 // default to ANSI code page
  2. wstring stringTowstring(string str, size_t m_encode = CP_ACP)
  3. {
  4. const char* cchar =str.c_str();
  5. wchar_t *m_wchar;
  6. int len = MultiByteToWideChar(m_encode, 0, cchar, strlen(cchar), NULL, 0);
  7. m_wchar = new wchar_t[len + 1];
  8. MultiByteToWideChar(m_encode, 0, cchar, strlen(cchar), m_wchar, len);
  9. m_wchar[len] = '\0';
  10. wstring strtemp = m_wchar;
  11. delete m_wchar;
  12. return strtemp;
  13. }
  14. int main()
  15. {
  16. string staa("你好,hello"); //在vs中,straa[0] 不能显示出“你”,需要转换成wstring
  17. wstring wstr = stringTowstring(staa);
  18. }

wstring 转 string 或者说 wchar * 转 char*

  1. string wstringTostring(wstring wstr, size_t m_encode = CP_ACP)
  2. {
  3. const wchar_t* wchar = wstr.c_str();
  4. char * m_char;
  5. int len = WideCharToMultiByte(m_encode, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL);
  6. m_char = new char[len + 1];
  7. WideCharToMultiByte(m_encode, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL);
  8. m_char[len] = '\0';
  9. string str = m_char;
  10. delete m_char;
  11. return str;
  12. }

UTF8 转换成GBK2312

  1. char* CWininetHttp::UtfToGbk(const char* utf8)
  2. {
  3.     int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
  4.     wchar_t* wstr = new wchar_t[len + 1];
  5.     memset(wstr, 0, len + 1);
  6.     MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
  7.     len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
  8.     char* str = new char[len + 1];
  9.     memset(str, 0, len + 1);
  10.     WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
  11.     if (wstr) delete[] wstr;
  12.     return str;
  13. }
  14. string staa("你好,hello");
  15. cout << staa[0] << endl;
  16. wstring wstr = stringTowstring(staa);
  17. string strd = wstringTostring(wstr);


  gb2312转换成utf8

  1.     string gb2312_to_utf8(const char* gb2312)
  2.     {
  3.         int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
  4.         wchar_t* wstr = new wchar_t[len + 1];
  5.         memset(wstr, 0, len + 1);
  6.         MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
  7.         len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
  8.         char* str = new char[len + 1];
  9.         memset(str, 0, len + 1);
  10.         WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
  11.         string strTemp = str;
  12.         if (wstr)
  13.             delete[] wstr;
  14.         if (str)
  15.             delete[] str;
  16.  
  17.         return strTemp;
  18. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/123147
推荐阅读
  

闽ICP备14008679号