【计算机学习笔记】GB2312、GBK、Unicode等字符编码的理解
创作时间:
作者:
@小白创作中心
【计算机学习笔记】GB2312、GBK、Unicode等字符编码的理解
引用
CSDN
1.
https://blog.csdn.net/RCHT1_Hideonbush/article/details/134897632
本文详细介绍了GB2312、GBK、Unicode等字符编码方式及其应用,涵盖了字符编码的基本概念、Unicode与UTF-8/UTF-16/UTF-32的关系、以及在文本文件和编程中的具体应用。文章通过代码示例和实际应用展示了不同编码方式的差异,适合对计算机编程和字符编码感兴趣的读者。
几个常见的编码方式
- GB2312:早期的汉字编码,覆盖6000+个常用汉字,无法处理生僻字或者古文
- GBK:收录20000+个汉字和符号,包括繁体字生僻字等
- GB18030:较新的汉字字集,与 GB 2312-1980 和 GBK 兼容,共收录汉字 70000+ 个,采用多字节编码,每个字可以由 1 个、2 个或 4 个字节组成
GB2312和GBK均属于2字节定长编码,和ASCII混编,ASCII区字符固定占用1字节,汉字区字符固定占用2字节 - Unicode:为世界上所有字符都分配了一个唯一的数字编号,目前编号范围从 0x000000 到 0x10FFFF,一共17个平面,每个平面有65536个码点
Unicode和UTF-8、UTF-16、UTF-32的关系
Unicode只规定了每个字符的编号,但没有规定二进制码如何存储,而UTF-8、UTF-16、UTF-32就是Unicode的二进制存储实现方案
- UTF-8:使用变长编码,编号小的使用的字节就少,编号大的使用的字节就多。使用的字节个数从 1 到 4 个不等,实现了对 ASCII 码的向后兼容,网络传输一般选择这种方式节省网络资源。编码规则:
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
- 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
- 例如在
U+0080
到
U+07FF
之间的字符,UTF - 8 用 2 个字节来编码。其格式为
110xxxxx 10xxxxxx
。编码时,将 Unicode 码点的二进制表示分为两部分,前 5 位放在第一个字节的
xxxxx
位置,后 6 位放在第二个字节的
xxxxxx
位置。
- UTF-16:使用变长编码
- 对于编号在
U+0000
到
U+FFFF
的字符(常用字符集),直接用两个字节表示。 - 编号在
U+10000
到
U+10FFFF
之间的字符,需要用四个字节表示。 - UTF-16有字节的顺序问题(大小端),所以就有 UTF-16BE 表示大端,UTF-16LE 表示小端。
- 会在字符开头添加
FEFF
(不知道干什么用,网上也找不到资料)
- 对于编号在
- UTF-32:定长编码,直接将码点转换为4字节的二进制表示形式,消耗较大,用得比较少,同样也有字节顺序问题
字符编码的应用
文本文件里的字符
- ANSI:在一些文本编辑器里(例如记事本)会看到ANSI编码方式。ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码,例如中国的计算机ANSI编码即为GBK,美国的计算机ANSI编码即为ASCII
如下图所示, 记事本和rider编辑器右下角都会有显示此文件的编码方式
在这些文本编辑器里选择转换编码方式的话,则文本的内容不变,改变编码方式。选择重新加载,则内存内容不变,重新以新的编码方式解析成文本
下面展示分别使用ANSI(GBK),UTF-8,UTF-16,UTF-32四种方式存储“你好我是123456”这个字符串所需大小:
- ANSI(GBK):汉字占2字节,ASCII字符占1字节
- UTF-8:汉字占3字节,ASCII字符占1字节
- UTF-16:汉字占2字节,ASCII字符占2字节,UTF-16还有在开头添加的2字节
- UTF-32:每个字符4字节,因为记事本没有UTF32,我在Rider修改编码方式
用VS打断点测试一下大端序UTF-16的内存情况,下图为文本文件存储的22字节内容:
除了开头添加的FEFF,“你好我是”这四个汉字的Unicode编号分别为
可以发现和内存里汉字的内容和字符编码相对应,后面的
3100
,
3200
这些就不一个个查了
编程中的字符
- C/C++中窄字符和宽字符共用,窄字符即
string(char)
,宽字符即
wstring(wchar_t)
,Python/C#这种高级语言里的string默认为宽字符 - 窄字符字符串以单个字节为单位,输出长度是输出字节数;宽字符字符串以字符为单位,输出长度是输出字符数
字符串字面量
C++中存储窄字符串字面量的话,字符串编码方式和代码文本文件的编码方式有关,存储宽字符串字面量的话要在字符串前面加‘L’标记,在Python/C#之类的高级语言里则是直接存储宽字符的字面量
例如下面这一段C++代码,如果文件格式为GBK,则输出14,如果为UTF-8,则输出18
#include <iostream>
int main()
{
std::string str = "你好我是123456";
std::cout << str.size();
return 0;
}
下面是C++,Python,C#代码分别存储宽字符并输出大小的代码:
#include <iostream>
int main()
{
std::wstring str = L"你好我是123456";
std::cout << str.size();
return 0;
}
s = "你好我是123456"
print(len(s))
using UnityEngine;
public class StartUp : MonoBehaviour
{
private void Start()
{
string str = "你好我是123456";
Debug.Log(str.Length);
}
}
高级语言的窄字符
刚刚说了,Python/C#这种高级语言的字符串默认采用宽字符,如果要在高级语言使用窄字符,则需要对字符串使用encode之类的函数变成高级语言的byte数组
print(len("你好我是123456".encode("utf-8")))
print(len("你好我是123456".encode("gbk")))
using System.Text;
using UnityEngine;
public class StartUp : MonoBehaviour
{
private void Start()
{
string str = "你好我是123456";
byte[] utf8Bytes = Encoding.GetEncoding("UTF-8").GetBytes(str);
byte[] gbkBytes = Encoding.GetEncoding("GBK").GetBytes(str);
Debug.Log("UTF-8编码后的长度" + utf8Bytes.Length);
Debug.Log("GBK编码后的长度" + gbkBytes.Length);
}
}
热门推荐
紫薇斗数中天机天梁命格的特征与影响是什么
数学建模:人口增长问题(基于指数增长模型和阻滞增长模型)
如何在UI设计中处理信息过载
揭秘明朝宫廷大宴群臣的礼仪:一场融合音乐舞蹈的盛大仪式
宇宙四大基本力:强核力、电磁力、弱核力和引力
压路机型号详解:从微型到超重型全面解析
心学问心理教育,孩子对规则理解不深?规则意识与行为规范的引导
宝可梦剑盾属性提升攻略:个体值、努力值详解
口袋妖怪白金版:值得培养的精灵宝可梦推荐
寻找“结婚搭子”时,一定要参考这4个择偶条件
全国教育资源最丰富的10座城市,首都遥遥领先,六朝古都名列第三
利用唐奇安通道进行交易突破策略
若是唐玄宗不干涉,任由哥舒翰固守,唐军能在潼关挡住安禄山吗?
碳信用流转:撬动万亿绿色经济的隐形杠杆
联通古往今来的中国人,成语是文化的道路
心理援助:如何理解与养育"高敏感"儿童
如何帮助孩子提高成绩
“野猪猎人”要来了?猎捕野猪有多难?
欧冠1/8决赛次回合:国际米兰主场迎战费耶诺德,谁能晋级八强?
全画幅和半画幅的区别:数字越小等级越高,明白4点改变你的想法
稀释股份对股票价格的影响是什么?
为什么男性一到中年就"发福"?中医西医全方位解析及调理方案
离异孩子监护人可以变更吗
变更孩子监护人的流程是怎样的
《古埃及史》:一部独特的古埃及学研究著作
比特币波动性与地缘政治事件:交易策略与风险管理
旧书如何找到更多新知己?
她亲手培养病毒治愈自身癌症,“自我试验”能推动科学进步吗?
足浴行业薪资制度怎么设计?
汤锅选什么材质的最好?汤锅的选购方法