唯一的编号
(称为“码点”或“代码点”)表示
哪些字符(如字母、数字、符号、汉字等)ASCII
:最基本的字符集!
包含128个字符(英文字母、数字、常用标点、控制字符)ISO-8859 系列
:扩展了ASCII,用于西欧、东欧等不同语言区域GB2312 / GBK / GB18030
:中国国家标准字符集,包含简体汉字、拉丁字母、数字等Big5
:繁体中文常用字符集JIS X 0208
:日本常用字符集(包含汉字和假名)Unicode
:最重要的现代字符集!
目标是包含世界上所有书写系统的所有字符,并为每个字符分配一个唯一的码点字符集中的码点
转换成计算机能够存储和传输的二进制序列(字节序列)
的规则。如何存储和传输
字符集中的字符的问题ASCII 编码
:最简单的编码,直接将 ASCII 码位(0-127)存储为一个字节(最高位为0)。例如 A
的码位是 65,编码后就是字节 0x41
(二进制 01000001
)ISO-8859-1 编码
:直接将码位(0-255)存储为一个字节GBK 编码
:对于 ASCII 范围内的字符(0-127),用一个字节表示(与 ASCII 兼容)。对于汉字和其他扩展字符,用两个字节表示。编码规则有特定的映射表UTF-8
: 最流行、最重要的 Unicode 编码方式之一。它是一种变长编码
,使用 1 到 4 个字节来表示一个 Unicode 码位UTF-16
:使用 2 或 4 个字节来表示一个 Unicode 码位UTF-32
:使用固定的 4 个字节来表示每一个Unicode 码位字符集
决定有哪些字符,字符编码
决定怎么存/传字符(字符集码位到字节的映射规则) ASCII
既是一个字符集
,也是一个编码方案
,并且是一体的。它定义了字符集(包含哪些字符)同时也定义了这些字符如何用数字表示(编码)。
ASCII 是美国信息交换标准代码,是最早
的一种字符集,由美国标准协会(ANSI)在 1963
年制定,用于解决字符标准化和跨平台通信
需求,便于计算机统一处理英语文本。
ASCII字符集特点:
128
个字符,33
个控制字符(0-31与127),95
个可打印字符 不可打印
的,包括控制字符,回车键、换行键、空格、删除等可打印
的,包括字母、数字、标点符号等ASCII字符集标准码表:
ASCII 编码是一种将字符转换为数字
(并最终转为二进制)的规则,它是对ASCII字符集
中字符的具体编码方式。每个 ASCII 字符用 7 位二进制数表示,对应一个十进制值(0~127)。
ASCII编码特点:
7 位(bit)
编码,通常在存储或传输时补成一个完整的8
位字节(byte),最高位补0
ASCII编码示例表:
字符 | 十进制 | 二进制 |
---|---|---|
A | 65 | 01000001 |
a | 97 | 01100001 |
0 | 48 | 00110000 |
空格 | 32 | 00100000 |
! | 33 | 00100001 |
Z | 90 | 01011010 |
ASCII扩展于1981
年由IBM在其PC中首次大规模实施,主要原因是原始ASCII的7位限制无法满足多语言需求和8位硬件潜力。扩展增加了128个字符(128-255
),包括符号、图形和西欧语言字符。
扩展 ASCII 的方式:
标准 ASCII
,范围0-127
,包含英文字符、数字、符号、控制字符扩展 ASCII
,范围128-255
,包含特殊拉丁字母、图形符号等常见扩展 ASCII 版本(扩展部分没有统一标准
,不同厂商定义了不同的字符表):
字符集名 | 简称/编号 | 特点 | 典型用途 |
---|---|---|---|
ISO 8859-1 | Latin-1 | 欧洲最常用,支持英语、西班牙语、德语、法语等 | HTML 网页、Linux 系统 |
Windows-1252 | ANSI/CP1252 | 微软对 Latin-1 的扩展,加入了 “©™” 等常见字符 | Windows 平台默认编码 |
Mac Roman | Apple Macintosh 系统使用,支持法语、西语等 | 早期 Mac OS 系统 | |
ISO 8859-5 | 扩展 ASCII 用于西里尔字母(俄语) | 东欧国家 |
扩展ASCII 编码方式:
0–127
:标准 ASCII 保持不变128–255
:扩展字符区总结一句话:
扩展 ASCII 是为了解决标准 ASCII 无法支持国际字符的问题,但由于缺乏统一标准(不同系统的扩展方式不同
),最终被 Unicode(如 UTF-8) 所取代。
GB2312
是一个既包含字符集
也定义了编码规则
的国家标准。
随着计算机在中国的普及,中国需要一种适合处理简体汉字的编码方案,因为早期的英文ASCII编码(仅支持128个字符)无法满足中文使用需求。中国大陆在1980
年代初期推出的一种汉字编码字符集
,主要用于简体中文
信息的处理和交换。
GB2312字符集组成:
6763
个汉字) 682
个) 128
个),属于兼容范围GB2312 字符集使用分区管理:
94
个区,每区包含94
个位,形成94×94的编码矩阵,总计8836
个码位(也称为区位码
) 01-09
区:收录除汉字外的682
个全角字符10-15
区:空白未使用(预留扩展)16-55
区:一级汉字(3755
个),按汉语拼音排序56-87
区:二级汉字(3008
个),按部首/笔画排序88-94
区:空白未使用(预留扩展)区位码 = 区号 + 行号 + 列号
,也可以说是区位码 = 区号 + 位号
(后续字符编码会用到)01-09区:除汉字外的 682 个全角字符
(0,0)
处是没有定义字符的,每个区有定义字符的区域在(0,1) ~ (9,4)
,所以每个区刚好包含94
个码点16-55区:收录 3755 个一级汉字,即常用汉字
'饼'
在第 17
区的第 9
行第 3
列,所以其对应的区位码:区号 + 行号 + 列号 = 1793
56-87区:收录 3088 个二级汉字,即次常用汉字
'侃'
在第 57
区的第 0
行第 9
列,所以其对应的区位码:区号 + 位号 = 5709
两个字节
表示(兼容的ascill
依然单个字节
) 0101-9494(01区的01位 到 94区的94位)
区号
和位号
分别加上 0xA0(十进制为160)
就是GB2312编码 01-94
变成了161-254
(对应十六进制0xA1-0xFE
)0xA1A1 - 0xFEFE
举例:‘侃’字的存储方式
217
(对应十六进制为0xD9
)169
(对应十六进制为0xA9
)‘侃’
字存储方式十进制为217 169
(对应十六进制为0xD9 0xA9
)public static void main(String[] args) throws UnsupportedEncodingException {
byte[] bytes = "侃".getBytes("GB2312");
System.out.print("字节(十进制): ");
for (byte b : bytes) {
// & 0xFF 把负数转为无符号正整数
System.out.print((b & 0xFF) + " ");
}
System.out.println();
System.out.print("字节(十六进制): ");
for (byte b : bytes) {
// 0xFF & b 用于转无符号整数
System.out.printf("%02X ", b & 0xFF);
}
}
输出结果:
字节(十进制): 217 169
字节(十六进制): D9 A9
为什么区号
和位号
都需要加上 0xA0(十进制为160)
?
01
开始的,只有都加上160
,才能避开 ASCII 和其他编码冲突十六进制范围 | 十进制 | 是否适合 GB2312 用作编码 | 原因 |
---|---|---|---|
0x00–0x7F | 0–127 | ❌ | 保留给英文及控制字符 |
0x80–0x9F | 128–159 | ❌ | ISO 控制符、编码冲突 |
0xA1–0xFE | 161–254 | ✅ ✅ ✅ | 国际标准、终端兼容、无冲突 |
单字节
部分 0x00 到 0x7F(十进制 0 到 127)
0x00–0x7F
,就可以直接当成 ASCII 字符来解释双字节
部分 0xA1 到 0xFE(十进制 161 得 254)
这个范围内(GB2312 标准定义的有效区域) GBK于1995
年推出,是为了解决GB2312无法覆盖所有汉字(如生僻字
和繁体字
),GBK扩展GB2312字符集,支持更多生僻字、繁体字及少数民族文字。
GBK字符集组成:
单字节
部分(ASCII) 双字节
部分(汉字和其他符号) 0x81–0xFE
(129-256),共126
位0x40–0xFE
(64-256),除0x7F
,共191
位21886
个字符 GBK 和 GB2312 虽然有相似的结构(比如都使用区位码
的概念),但它们在编码范围、字符数量、区位定义等方面存在明显区别。
特征 | GB2312 | GBK |
---|---|---|
编码方式 | 双字节 | 双字节 |
区的数量 | 最多 94 个区 | 最多 126 个区(范围更广) |
每区字符数量 | 最多 94 个 | 最多 191 个(不再固定 94) |
兼容区位结构 | ✅ 是 | ✅ 基于并扩展 |
GBK编码表:
0x81-0xFE
,一共126个分区0x40–0xFE
,排除0x7F
和0xFF
(后面解释),实际就190个位置… 省略中间的
GBK编码表为什么区号从0x81
开始,位号从0x40
开始,而且要排除0x7F
和0xFF
?
首字节0x81
对应十进制129
,这样就避开了标准ASCII0-127
的范围了。次字节从0x40开始也是为了避开控制字符(兼容ASCIl和扩展字符)
0x7F
在 ASCII 表中是 DEL(删除)控制字符
,在很多系统(特别是 Unix、DOS)中,0x7F 被保留用作控制功能。为避免误解或触发系统控制行为,被明确排除在 GBK 编码双字节的第二字节之外。
0xFF
是字节中的最大值
,在很多编码协议中具有特殊含义,比如表示结束、填充、掩码等。它在一些通信协议中会被当作控制字节,因此也被排除以确保兼容性和稳定性。
GB2312编码表区号和位号都是十进制
,而且需要同时+160,而GBK则规则简单一些,直接就是十六进制
的区号加位号即可,下面我们从GBK的编码表中找下‘侃’
字,如下也是0xD9A9
,这也就说明了GBK是兼容GB2312
的
Unicode是1991
年一种国际标准字符集,旨在为全球所有语言
的每个字符分配一个唯一的编码
(称为码点),解决不同字符集间的兼容性问题。
解决的根本问题
核心设计原则
通用性
: 包含所有现代及许多历史书写系统的字符,以及大量符号(数学、技术、货币、标点、表情符号等)唯一性
: 每个字符(或可组合字符的一部分)都被分配一个唯一的码点
。这个码点是一个数字(通常表示为U+XXXX
,其中XXXX是4-6位的十六进制数) 无歧义
: 一个码点永远只对应一个字符(语义上),反之亦然(理想情况下)编码空间与平面
U+0000
到U+10FFFF
),总计超过100万
个可能的码点17
个平面,每个平面包含65,536(2^16)
个码点基本多语言平面BMP
是最重要的,包含了世界上最常用的字符(U+0000到U+FFFF)Unicode的实现:编码形式
字符
和码点
的映射关系
,但它本身不规定字符在计算机中的存储方式(即编码方案)
UTF-8
:最常用;可变长度(1–4 字节);兼容 ASCII;在互联网上使用最广泛UTF-16
:可变长度(2 或 4 字节);Windows 系统常用UTF-32
:固定长度(4 字节);适合需要快速随机访问的系统固定长度
的Unicode编码方案,每个字符始终使用32位(4字节)
表示32
位二进制整数存储 变长
的Unicode字符编码方式,它使用2字节或4字节
来表示一个字符一个16
位的代码单元来表示 两个16位
的代码单元(称为代理对
)来表示 减去0x10000
(0x1F60A - 0x10000 = 0xF60A)高10位
0x3D和低10位
0x20A0xD800
相加,得到高位代理
(0x3D + 0xD800 = 0xD83D)0xDC00
相加,得到低位代理
(0x20A + 0xDC00 = 0xDE0A) UTF-16 和 UTF-32 都是多字节编码(每个代码单元占用 2 或 4 个字节),因此在存储或传输时,字节顺序(大小端)
至关重要。这就是字节顺序标记(BOM)
存在的原因。
字节顺序
大端(Big-Endian, BE)
:高位字节在前,低位字节在后(类似人类读书方式,先左后右) 小端(Little-Endian, LE)
:低位字节在前,高位字节在后(就是大端的倒序) 字节顺序标记BOM
0xFE 0xFF
0xFF 0xFE
0x00 0x00 0xFE 0xFF
0x00 0x00 0xFE 0xFF
总结对比表
编码方式 | 字节序 | 示例字符 U+1234 | 存储字节序列 | BOM(文本文件开头) |
---|---|---|---|---|
UTF-16LE | 小端 | U+1234 | 34 12 | FF FE |
UTF-16BE | 大端 | U+1234 | 12 34 | FE FF |
UTF-32LE | 小端 | U+00001234 | 34 12 00 00 | FF FE 00 00 |
UTF-32BE | 大端 | U+00001234 | 00 00 12 34 | 00 00 FE FF |
大小端作用对比
UTF-8(8-bit Unicode Transformation Format)是Unicode字符集的一种可变长度
字符编码,能够表示Unicode标准中的任何字符(覆盖范围U+0000至U+10FFFF)。
UTF-8 针对不同的 Unicode 字符的编码规则如下:
不同字符通过 UTF-8 编码之后,存储在计算机中的内容用1~4
字节来存储,计算机通过不同字节不同前缀
区分(上图二进制红色固定前缀)
字节分配规则:ASCII字符
用1字节
(U+0000~U+007F),希腊字母
等用2字节
(U+0080~U+07FF),中文字符
用3字节
(U+0800~FFFF),生僻字符
用4字节
(U+10000以上)
UTF-8编码方式
'中'
为例,Unicode码点U+6C49
转为10进制:20013
3字节存储
将码点转换为二进制
,20013 —> 01001110 00101101(空缺位置用0填充,凑到8bit的整数倍)3
字节存储,其十六进制形式是0xE4 0xB8 0xAD