字符编码(UTF-8,16,32 和GBK和ASCLL码)
迅速通读本文:
计算机一开始是美国人弄出来的,我们都知道二进制可以表示很多数字,但是无法直接表示字符对吧,出现了一个需求要求表示字母和一些常见的符合,于是想到一个办法,类似于字典一样或者说map,用一个值去对应一个个字符,所以这个“字典”就是ascall码值,而且对应的一个个字符都是1个字节(8位)来存放这些字符。
随着时间的发展啊对吧,不同国家有不同的语言需求,所以原来的单纯的ascll码值这个字典以及不满足于人们需求。就有了各种需求,中国人弄了GBK(编码存了大量的简体 甚至生僻字等等满足国内的需求),日本人弄了一个Shift_JIS编码,台湾也有自己的。但是后来国家与国家之间的人们有交流需求,不同的编码编写的文件,用不对应的编码方式来打开会出现乱码啊。
所以为了统一标准 国际上搞了一本字典,记录这个世界上所有的语言,以及符号等等这样大家都统一了,也就是Unicode,它相当于一个指导,还不是编码值,也就是定义了一系列的变化对应的值呢还没实现,因为前面我们说了类似于“字典”的模式,键跟值是要一一对应的,那么谁来实现了这个需求呢? 目前实现它的有变长字符UTF-8, 定长的:utf-16 ,UTF-32。
一、ASCII:计算机的 "基础英语词汇表"
1. 诞生背景:让计算机认识字母
20 世纪 60 年代,计算机只能处理 0 和 1,但人类需要输入字母。于是美国人搞了个「英语专用翻译手册」——ASCII 码。它规定:
A
= 65(二进制01000001
)a
= 97(二进制01100001
)0
= 48(二进制00110000
)
意思就是:ascll码值跟这个字符一一对应 这样就可以实现把字符存储到计算机中啦。
2. 存储大小:1 字节的 "小盒子"
ASCII 用 1 字节(8 位)存储一个字符,总共能表示 128 个符号(2^7,最高位固定为 0)。比如
'A'
的二进制是01000001
,存进计算机就是这 8 位。
3. 致命缺陷:只能装 "英语单词"
实际上不仅仅英文单词这里只是简单的阐述实际上ASCLL码值还能表示一些其他的字符,但是当然很难满足我们其他国家的人啊,比如我们用汉语
简单来说ASCII 就像一本只有 26 个英文字母 + 数字 + 标点的字典:
- 想存中文?没位置!
- 想存俄语字母?没位置!
- 甚至想存笑脸😀?更没位置!
灵魂画图 1:ASCII 的 "小盒子"
+--------+
| 01000001 | → 存'A'
+--------+1字节空间
(每个盒子只能装 1 个英文字母,多了装不下)
二、Unicode:给全世界字符 "分配身份证"
1. 为什么需要 Unicode?
20 世纪 90 年代,互联网普及,各国语言冲突爆发:
- 中文用 GB2312,日文用 Shift_JIS,不同编码文件互开就是乱码!
- 程序员吐槽:"我写个程序,存中文用 GBK,存日文得换编码,太麻烦了!"
2. Unicode:全球字符的 "统一身份证号"
Unicode 像一本全球字典,给每个字符分配唯一编号(码点):
'A'
→ U+0041'中'
→ U+4E2D😀
→ U+1F600
3. 注意:Unicode≠编码!
Unicode 只是 "字符编号表",就像字典里 "中" 字的编号是 4E2D,但怎么把这个编号存进计算机?需要 UTF 家族来 "翻译"。
三、UTF-8:最聪明的 "变长翻译官"
1. 为什么叫 "变长"?
UTF-8 的核心思路:
- 英文字母用 1 字节存(兼容 ASCII)
- 欧洲字母用 2 字节存
- 中文 / 日文用 3 字节存
- 罕见符号(如😀)用 4 字节存
2. 编码规则:用 "前缀" 标记字节数
UTF-8 的每个字节开头有特殊前缀,像快递盒上的 "尺寸标签":
- 1 字节字符:前缀
0
→ 存 ASCII 字符 - 2 字节字符:前缀
110
+10
- 3 字节字符:前缀
1110
+10
+10
- 4 字节字符:前缀
11110
+10
+10
+10
灵魂画图 2:UTF-8 的 "快递盒"
+--------+ 1字节盒(装英文):前缀0
| 0xxxxxxx | +--------+ +--------+ 2字节盒(装欧洲字符):
| 110xxxxx | | 10xxxxxx | +--------+ +--------+ +--------+ 3字节盒(装中文):
| 1110xxxx | | 10xxxxxx | | 10xxxxxx | +--------+ +--------+ +--------+ +--------+ 4字节盒(装emoji):
| 11110xxx | | 10xxxxxx | | 10xxxxxx | | 10xxxxxx |
3. 实例:' 中 ' 字的 UTF-8 编码
'中'
的 Unicode 码点是 U+4E2D(二进制100111000101101
)
用 3 字节 UTF-8 存储:
- 把二进制码点填入 3 字节的 "数据位":
plaintext
1110xxxx 10xxxxxx 10xxxxxx ↓ ↓ ↓ 11100100 10111000 10101101
- 转成十六进制:
0xE4 0xB8 0xAD
,共 3 字节。
四、UTF-16 和 UTF-32:两种 "极端" 的翻译方式
1. UTF-32:简单粗暴的 "定长盒子"
- 每个字符固定占 4 字节,不管是英文还是中文
- 优点:计算字符位置简单(第 n 个字符在 4*n 字节处)
- 缺点:存英文太浪费空间!
'A'
存成00000041
,4 字节!
灵魂画图 3:UTF-32 的 "傻大盒子"
plaintext
+--------+--------+--------+--------+
| 00000041 | | | | → 存'A',浪费3字节
+--------+--------+--------+--------+
2. UTF-16:折中方案的 "中等盒子"
- 常用字符占 2 字节,罕见字符占 4 字节
- Windows 和 Java 的默认编码,平衡空间和效率
- 例子:
'A'
存 2 字节,'中'
存 2 字节,😀
存 4 字节 - 3. 为什么会有他们俩 以及用在什么地方
- 计算机算机处理 UTF - 8 编码的字符时,需要根据编码规则来解析字符,确定每个字符占用的字节数等,这比处理固定长度编码(如 UTF - 32)要复杂一些,会消耗更多的 CPU 时间和计算资源。例如,在对 UTF - 8 编码的字符串进行搜索、排序等操作时,计算机需要花费更多时间来处理。
- 他们俩一般用再---》比如嵌入式开发的时候。
五、为什么 UTF-8 成为互联网 "顶流"?
1. 三大优势吊打其他编码:
- 兼容 ASCII:英文文件用 UTF-8 存和 ASCII 一样大,无缝衔接老程序
- 节省空间:中文占 3 字节,比 UTF-32 的 4 字节省 25%
- 抗错误能力强:某个字节出错,只影响当前字符,不会破坏后续内容
2. 数据证明:
- 全球 85% 的网页用 UTF-8(2023 年统计)
- GitHub、Linux、HTML5 默认编码都是 UTF-8
六、编码那些坑:为什么会出现 "乱码"?
1. 经典场景:用错误编码打开文件
比如:
- 一个 UTF-8 编码的中文文件,用 GBK 编码打开
- 计算机误解了字节组合:
plaintext
UTF-8的"中"是E4 B8 AD(3字节) GBK把E4 B8当成一个字符,AD当成另一个字符 结果显示为乱码"涓"
灵魂画图 4:乱码的真相
plaintext
正确翻译(UTF-8): 错误翻译(GBK):
+---+---+---+ +---+---+---+
|E4|B8|AD| → '中' |E4|B8|AD| → 乱码字符
+---+---+---+ +---+---+---+
2. 程序员必知:编码转换的陷阱
- 从 UTF-8 转 UTF-16:简单,按规则转换
- 从 GBK 转 UTF-8:可能丢失字符(GBK 只包含简体中文,不包含 emoji 等)
七、总结:编码的本质是 "翻译协议"
- ASCII:计算机的英语入门教材,1 字节存英文
- Unicode:全球字符的字典,给每个字符发 "身份证"
- UTF-8:最聪明的翻译官,用不同大小的盒子存字符,兼容英文又省空间
- 乱码:翻译官拿错了字典,把 "中文" 翻译成了 "火星文"
最后灵魂拷问:
为什么😀在 UTF-8 里占 4 字节?
因为它的 Unicode 码点 U+1F600 超过了 3 字节能表示的范围(3 字节最大到 U+10FFFF,而 U+1F600 在 U+100000 以上),只能用 4 字节存啦!
附录:常见字符编码对比表
字符 | Unicode 码点 | UTF-8 (字节) | UTF-16 (字节) | UTF-32 (字节) |
---|---|---|---|---|
'A' | U+0041 | 0x41 (1) | 0x0041 (2) | 0x00000041 (4) |
' 中' | U+4E2D | 0xE4B8AD (3) | 0x4E2D (2) | 0x00004E2D (4) |
'€'(欧元符号) | U+20AC | 0xE282AC (3) | 0x20AC (2) | 0x000020AC (4) |
'😀' | U+1F600 | 0xF09F9880 (4) | 0xD83DDE00 (4) | 0x0001F600 (4) |
拓展:
a. 为什么既然utf8都这么方便了既可以兼容ascll码值还是变长的会识别字符选择合适的内存大小存储字符还要存在utf-16和utf-32?
utf-8,这个8呢是指它存最小内存单位是8字符也就是简单的字符(包括ascll码值中的)它会选择一个字符的,对于复杂一点的。。中文3字节等等
你发现没有很神奇对吧!它会自动耶好腻害。那你就失算了,你说帮你自动识别了这个过程要不要消耗资源(特别是时间资源,肯定会调算法啊 排序啊等等) 那它这样影响效率了啊,那怎么办
所以就有定长的啦:一个是utf-16 16位 2个字节而已(最小2个字节定长的)它的好处就是大多字符编码都是2字节这样使用效率会好很多,但是一点点缺点就是可能不够用啊 才两个字节,这个时间有很多语言它可能表示不了。
所以为了进一步满足需求语言足够用的需求那就使用了utf-32,那缺点是啥内存太大了呗,比如我存一个字符'A'上来好家伙就4字节了。
用处
你猜? 嵌入式方面这种偏向机械的内部编码会用谁,当然是为了效率肯定用utf-16.
utf-8 是很通用的所以啊大多会呗用来网站啊,操作系统,一些工具啊 编译器等等比如你的IDEA,VS2020啊,等等
gbk
国内的GBK为什么还在用不改用utf-8,其实就跟c++要兼容c语言一样,当初出gdb的时候国内很多系统啊都是用了gdb啊。 目前也有一些操作系统专门位gdb编码啊比如windows xp 这个你可能听过默认中午编码就是gdb。
它其实设计的很巧妙的,2个字节存中文,内存上大大的优化很高的,但是吧。。。时代在召唤,必然迈向国际化呗。