【计算机学习笔记】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);
}
}
热门推荐
派币技术揭秘:是财富机遇还是骗局?
韩国热捧派币,投资需警惕骗局
灯的多重象征,让你的文案闪闪发光
破解孩子沉默难题:5大技巧改善亲子沟通
教育孩子先懂这5点,让亲子关系更和谐
闵行七宝:千年古镇里的亲子游乐园
去亚龙湾沙滩坐几路车?公交路线全解析
《捉泥鳅》:一首儿歌里的文化密码
北京两座古寺:雍和宫的皇家气派与卧佛寺的铜佛奇观
动画图解嵌入式常见的通讯协议:SPI、I²C、UART、红外
四年级数学课堂管理新招数:让学生成为课堂的主角
四年级数学教学新路径揭秘
四年级数学成绩逆袭秘籍,学霸都在用!
自来水存在多重隐患,专家建议安装净水器保安全
富含17种氨基酸,牛蒡助力冬季养生防流感
老年痴呆早期预警信号,这些细节别忽视
湖北原矿绿松石价格波动,收藏市场受冲击
猪血:秋冬养生的营养之选
鸭血PK猪血,谁才是补血王者?
连衣裙的时尚革命:从维多利亚到社交媒体时代
复方甘草口服溶液使用指南:从用量到禁忌,这些要点要记牢
甘草止咳药饮食禁忌:孕妇禁用,高血压患者慎食
狗狗腹泻的饮食管理:白米饭配鸡肉的正确喂食法
狗狗拉稀警惕犬瘟热和犬细小病毒,定期接种疫苗是关键
科学护理让贵宾犬阿拉斯加远离拉稀困扰
科学选购狗粮指南:让狗狗远离拉稀困扰
贝加尔湖:历代文人的神秘北冥
贝加尔湖:庄子哲学中的北冥象征
七宝地铁站最新交通指南出炉!
茨菇当季,这些美味做法你get了吗?