【计算机学习笔记】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);
}
}
热门推荐
怀山药:秋冬养生新宠!
秋季滋补:山药的9种创意吃法
山药控糖新吃法,糖尿病友必看!
太阳能热水器DIY维修全攻略:从故障判断到维修技巧
西安高新至鄠邑高速复合通道:构建西南交通大动脉
鄠邑区大雾天高速管制,你被堵在路上了吗?
西户铁路改造加速,鄠邑区经济腾飞在即!
医用气相色谱仪:揭秘医学检测黑科技
AI赋能气相色谱仪:让科研工作更智能高效
气相色谱仪在化学分析中的应用
上门做年夜饭,10天赚2万?
2025丝路春晚:多元语言大赏!
冬季太阳能热水器故障怎么办?
太阳能热水器保温桶漏水?这些小妙招轻松搞定!
洗衣机排水管应该怎么疏通啊
四明山脉,上海人的后花园,17处自然奇观去过几处?
粤陕文旅新篇:华清宫与华山的“牵手”之旅
华山东峰饭店:观日出的最佳选择!
华裔球员陈达毅3分钟闪击热刺 本赛季英超4球 能否被国足归化?
陈达毅欲自主入籍,国际足联不允许,需足协帮忙,已被过度曝光
将乐动车站出发:玉华洞+天阶山完美一日游攻略
秋冬必备:蓝莓山药的神仙吃法
温县垆土铁棍山药:土壤的秘密
焦作山药丰收成"愁":产量激增至千万吨,价格暴跌56.67%
天空竞逐:全球航空业的爆发与中国商飞的突围
大飞机制造质量数字孪生一致性控制技术及应用|上海市科学技术奖
泰国坠机事件引担忧:小飞机没大飞机安全坐不得?听听开这两种飞机的飞行员怎么说
英格兰队动荡!9名球员退出+主帅下课,凯恩表达失望情绪
坐拥5位亿元先生,总身价13.78亿欧!如此英格兰居然还有两大短板?
自己的腰自己救!久坐族養腰7動作 緩解腰痛腿麻,趕緊練起來