什么是字符集
字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有: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位为英文字母和标点符号及运算符号等。
字符集:从符号(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 | 0xxxxxxx0000 0080-0000 07FF | 110xxxxx 10xxxxxx0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx0001 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_ACP0// default to ANSI code page
#define CP_UTF865001 // UTF-8 translation
string 转 wstring 或者说 char * 转 wchar*
这就是为了防止string类型的乱码,需要把string 转换成wstring.
在MFC中,Cstring str = wstring wstr.c_str();
//#define CP_ACP0 // default to ANSI code pagewstring stringTowstring(string str, size_t m_encode = CP_ACP){const char* cchar =str.c_str();wchar_t *m_wchar;int len = MultiByteToWideChar(m_encode, 0, cchar, strlen(cchar), NULL, 0);m_wchar = new wchar_t[len + 1];MultiByteToWideChar(m_encode, 0, cchar, strlen(cchar), m_wchar, len);m_wchar[len] = '\0';wstring strtemp = m_wchar;delete m_wchar;return strtemp;}int main(){string staa("你好,hello"); //在vs中,straa[0] 不能显示出“你”,需要转换成wstringwstring wstr = stringTowstring(staa);}
wstring 转 string 或者说 wchar * 转 char*
string wstringTostring(wstring wstr, size_t m_encode = CP_ACP){const wchar_t* wchar = wstr.c_str();char * m_char;int len = WideCharToMultiByte(m_encode, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL);m_char = new char[len + 1];WideCharToMultiByte(m_encode, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL);m_char[len] = '\0';string str = m_char;delete m_char;return str;}
UTF8 转换成GBK2312
char* CWininetHttp::UtfToGbk(const char* utf8){int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);wchar_t* wstr = new wchar_t[len + 1];memset(wstr, 0, len + 1);MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);char* str = new char[len + 1];memset(str, 0, len + 1);WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);if (wstr) delete[] wstr;return str;}string staa("你好,hello");cout << staa[0] << endl;wstring wstr = stringTowstring(staa);string strd = wstringTostring(wstr);
gb2312转换成utf8
string gb2312_to_utf8(const char* gb2312){int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);wchar_t* wstr = new wchar_t[len + 1];memset(wstr, 0, len + 1);MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);char* str = new char[len + 1];memset(str, 0, len + 1);WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);string strTemp = str;if (wstr)delete[] wstr;if (str)delete[] str;return strTemp;}
如果觉得《ASCII字符集 Unicode字符集下UTF-8 和UTF-16编码 GBK(GB2312)字符集》对你有帮助,请点赞、收藏,并留下你的观点哦!