【计算机学习笔记】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);
}
}
热门推荐
“拿出当仁不让的气势!”固安促进房地产业健康发展
黄山汤口镇:三大自然景观全攻略
说肺癌论EGFR基因突变:基因突变种类、治疗思路!
焦作两碗面:土信面与“中华第一面”
王者荣耀2024澜最强六神装:两套出装方案全攻略
保肺丸获权威研究背书,立冬补肺正当时
喜羊羊与灰太狼新作来袭,麒麟鼎的秘密揭晓
厦门文博会带你探秘鼓浪屿历史建筑
草莓大黄派
梵净山春秋游:一个季节两种风景,旅游最佳时节全解析
关节炎治疗新选择:独活寄生丸临床疗效达94.74%
鸭血粉丝汤、盐水鸭:最正宗的南京味道
一文读懂伤残鉴定:材料准备、流程步骤及注意事项
别再盲目补钙!大脚拇指疼痛的真相与应对指南
玉龙雪山摄影指南:如何拍出令人惊叹的雪山大片
游戏外挂制售被判重罚,法律和技术双重发力守护游戏公平
探讨民间礼仪文化:十岁女孩子生日,送什么礼物好?
如何用救助申请书模板打动人心?
惠州到云南自驾游,一路美景等你发现
2024年退休,北京市养老金怎么计算?工龄30年,能领到5000元吗?
看哭了!十部必看高分爱国电影
从基础步骤到日常护理:美甲持久美丽的秘诀
龙胆泻肝丸饭前吃还是饭后吃?答案在这里!
历年注册会计师通过率仅22%左右,2024年考试难度如何?
英语教育政策比较,不同国家的实践与启示
首届三大球运动会:体教融合显成效,职业体育寻突破
专家详解枸杞食用方法:5种方式各有利弊
SpaceX星舰火箭首次成功回收助推器,实现“筷子夹火箭”技术突破
脑梗发作前,身体3个部位可能发“硬”!出现一个就要警惕
维生素抗癌真相:A、B、C、D谁是真正的抗癌明星