让你秒懂字符集与编码:详解ASCII、GB2312、Unicode和UTF-8

一、字符集和字符编码概念

1、字符集 (Character Set)

  • 定义:一个预定义的字符集合,为每个字符分配一个唯一的编号(称为"码点"或"代码点")
  • 作用:定义能够表示哪些字符(如字母、数字、符号、汉字等)
  • 例子:
    • ASCII最基本的字符集!包含128个字符(英文字母、数字、常用标点、控制字符)
    • ISO-8859 系列:扩展了ASCII,用于西欧、东欧等不同语言区域
    • GB2312 / GBK / GB18030:中国国家标准字符集,包含简体汉字、拉丁字母、数字等
    • Big5:繁体中文常用字符集
    • JIS X 0208:日本常用字符集(包含汉字和假名)
    • Unicode最重要的现代字符集! 目标是包含世界上所有书写系统的所有字符,并为每个字符分配一个唯一的码点

2、字符编码 (Character Encoding)

  • 定义:一种将字符集中的码点转换成计算机能够存储和传输的二进制序列(字节序列) 的规则。
  • 作用:解决如何存储和传输字符集中的字符的问题
  • 例子:
    • 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 码位

3、关键区别与联系

  • 一个字符集可以有多种编码方式。这是理解它们区别的关键!
    • Unicode 字符集就有多种编码方式:UTF-8, UTF-16, UTF-32, 还有早期的 UCS-2 等
  • 一种编码方式通常对应一个特定的字符集(或兼容其子集)
    • UTF-8 编码只能表示 Unicode 字符集中的字符
    • GBK 编码对应 GBK 字符集(它是 GB2312 的扩展)
    • ASCII 编码只对应 ASCII 字符集(128个字符)
  • 总结一句话:字符集决定有哪些字符,字符编码决定怎么存/传字符(字符集码位到字节的映射规则)

一、ASCII(字符集/字符编码)

ASCII既是一个字符集,也是一个编码方案,并且是一体的。它定义了字符集(包含哪些字符)同时也定义了这些字符如何用数字表示(编码)。

1、ASCII字符集

ASCII 是美国信息交换标准代码,是最早的一种字符集,由美国标准协会(ANSI)在 1963 年制定,用于解决字符标准化和跨平台通信需求,便于计算机统一处理英语文本。

ASCII字符集特点:

  • ASCII定义了128个字符,33个控制字符(0-31与127),95个可打印字符
    • 前32个字符和最后一个是不可打印的,包括控制字符,回车键、换行键、空格、删除等
    • 后95个字符是可打印的,包括字母、数字、标点符号等
  • 适合英文,不支持中文、日文、韩文等非拉丁文字

ASCII字符集标准码表:

2、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

3、扩展ASCII

ASCII扩展于1981年由IBM在其PC中首次大规模实施,主要原因是原始ASCII的7位限制无法满足多语言需求和8位硬件潜力。扩展增加了128个字符(128-255),包括符号、图形和西欧语言字符。

扩展 ASCII 的方式:

  • 标准 ASCII 是 7 位,扩展 ASCII 将字符扩展为 8 位(1 字节),总数变为 256(0--255)
  • 标准 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 编码方式:

  • 编码位数:8 位(二进制),即一个字节
  • 编码范围:0--255
    • 0--127:标准 ASCII 保持不变
    • 128--255:扩展字符区
  • 可表示:
    • 各种语言的特殊字母(é, ñ, ü 等)
    • 图形符号(█, ░, ═)
    • 特殊符号(©, ®, °, ±)等

总结一句话:

扩展 ASCII 是为了解决标准 ASCII 无法支持国际字符的问题,但由于缺乏统一标准(不同系统的扩展方式不同),最终被 Unicode(如 UTF-8) 所取代。

二、GB2312(字符集/字符编码)

GB2312是一个既包含字符集也定义了编码规则的国家标准。

1、GB2312字符集

随着计算机在中国的普及,中国需要一种适合处理简体汉字的编码方案,因为早期的英文ASCII编码(仅支持128个字符)无法满足中文使用需求。中国大陆在1980年代初期推出的一种汉字编码字符集,主要用于简体中文信息的处理和交换。


GB2312字符集组成:

  • 1️⃣ 汉字字符(6763 个汉字)
    • 一级汉字:3755 个,常用汉字,按拼音顺序排列
    • 二级汉字:3008 个,次常用汉字,按部首结构排列
  • 2️⃣ 非汉字字符(共 682 个)
    • 拉丁字母(A--Z, a--z)
    • 希腊字母(α,β 等)
    • 日文假名(片假名)
    • 数字(0--9)
    • 标点符号(中英文)
    • 常用符号(如 ©,¥,℃)
  • 3️⃣ ASCII 字符(128 个),属于兼容范围

GB2312 字符集使用分区管理:

  • GB2312将字符集划分为94个区,每区包含94个位,形成94×94的编码矩阵,总计8836个码位(也称为区位码
    • 01-09区:收录除汉字外的682个全角字符
    • 10-15区:空白未使用(预留扩展)
    • 16-55区:一级汉字(3755个),按汉语拼音排序
    • 56-87区:二级汉字(3008个),按部首/笔画排序
    • 88-94区:空白未使用(预留扩展)
  • GB2312 字符集中字符的区位码 = 区号 + 行号 + 列号,也可以说是区位码 = 区号 + 位号(后续字符编码会用到)

01-09区:除汉字外的 682 个全角字符

  • 每个区的(0,0)处是没有定义字符的,每个区有定义字符的区域在(0,1) ~ (9,4),所以每个区刚好包含94个码点

16-55区:收录 3755 个一级汉字,即常用汉字

  • '饼' 在第 17 区的第 9 行第 3 列,所以其对应的区位码:区号 + 行号 + 列号 = 1793

56-87区:收录 3088 个二级汉字,即次常用汉字

  • '侃' 在第 57 区的第 0 行第 9 列,所以其对应的区位码:区号 + 位号 = 5709

2、GB2312字符编码

  • GB2312 规定对收录的每个字符采用两个字节表示(兼容的ascill依然单个字节
    • 第一个字节为"高字节",对应 94 个区(01-94区)
    • 第二个字节为"低字节",对应 94 个位(每个区对应的94个位置,也是01-94)
    • 这就看出区位码的最大范围是:0101-9494(01区的01位 到 94区的94位)
  • 区号位号分别加上 0xA0(十进制为160)就是GB2312编码
    • 第一个字节和第二个字节就由01-94变成了161-254(对应十六进制0xA1-0xFE
    • 此时GB2312编码对应范围就是0xA1A1 - 0xFEFE

举例:'侃'字的存储方式

  • 区号为57,也就是第一个字节为57,加上160为217(对应十六进制为0xD9
  • 位号为行号+列号为09,也就是第二个字节为09,加上160为169(对应十六进制为0xA9
  • 最终'侃'字存储方式十进制为217 169(对应十六进制为0xD9 0xA9
java 复制代码
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);
    }
}

输出结果:

java 复制代码
字节(十进制): 217 169 
字节(十六进制): D9 A9 

为什么区号位号都需要加上 0xA0(十进制为160)?

  • 因为区是一个字节,位是一个字节,这两个字节都是从01开始的,只有都加上160,才能避开 ASCII 和其他编码冲突
十六进制范围 十进制 是否适合 GB2312 用作编码 原因
0x00--0x7F 0--127 保留给英文及控制字符
0x80--0x9F 128--159 ISO 控制符、编码冲突
0xA1--0xFE 161--254 ✅ ✅ ✅ 国际标准、终端兼容、无冲突

3、GB2312如何兼容ASCII

  • 单字节部分
    • ASCII 码使用单字节表示,取值范围是0x00 到 0x7F(十进制 0 到 127)
    • 在 GB2312 中,0x00--0x7F 的字节值与 ASCII 完全相同
    • 因此,当你在一个以 GB2312 视作"编码"环境中读到一个字节,如果它落在0x00--0x7F,就可以直接当成 ASCII 字符来解释
  • 双字节部分
    • 双字节编码的两个字节都落在0xA1 到 0xFE(十进制 161 得 254)这个范围内(GB2312 标准定义的有效区域)
    • 程序将这个读到的"高位字节"(第一个字节)和紧随其后的"低位字节"(第二个字节)组合在一起,形成一个两字节的编码。然后,它去查询 GB2312 的码表,找到这个双字节编码对应的汉字或符号

三、GBK(字符集/字符编码)

1、GBK字符集

GBK于1995年推出,是为了解决GB2312无法覆盖所有汉字(如生僻字繁体字),GBK扩展GB2312字符集,支持更多生僻字、繁体字及少数民族文字。

GBK字符集组成:

  • 单字节部分(ASCII)
    • 范围:0x00--0x7F(0-127)
    • 包括:英文字母、数字、标点、控制字符等
  • 双字节部分(汉字和其他符号)
    • 第1字节:0x81--0xFE(129-256),共126
    • 第2字节:0x40--0xFE(64-256),除0x7F,共191
    • 理论编码空间:126 × 191 = 24066 个位置
    • 实际使用:21886 个字符
    • 包含字符
      • 全部的 GB2312 汉字(6763 个)
      • 扩展汉字(约 18000 个)
      • 常用繁体字
      • 日文假名
      • 希腊字母、俄文、西欧字符等
      • 图形符号、制表符等

2、GBK字符编码

GBK 和 GB2312 虽然有相似的结构(比如都使用区位码的概念),但它们在编码范围、字符数量、区位定义等方面存在明显区别。

特征 GB2312 GBK
编码方式 双字节 双字节
区的数量 最多 94 个区 最多 126 个区(范围更广)
每区字符数量 最多 94 最多 191 个(不再固定 94)
兼容区位结构 ✅ 是 ✅ 基于并扩展

GBK编码表:

  • 区号从0x81-0xFE,一共126个分区
  • 位号=行号+列号,从0x40--0xFE,排除0x7F0xFF(后面解释),实际就190个位置
  • 编码方式:第一个字节(区号)+ 第二个字节(位号)

... 省略中间的

GBK编码表为什么区号从0x81开始,位号从0x40开始,而且要排除0x7F0xFF

首字节0x81对应十进制129,这样就避开了标准ASCII0-127的范围了。次字节从0x40开始也是为了避开控制字符(兼容ASCIl和扩展字符)

0x7F 在 ASCII 表中是 DEL(删除)控制字符,在很多系统(特别是 Unix、DOS)中,0x7F 被保留用作控制功能。为避免误解或触发系统控制行为,被明确排除在 GBK 编码双字节的第二字节之外。

0xFF字节中的最大值,在很多编码协议中具有特殊含义,比如表示结束、填充、掩码等。它在一些通信协议中会被当作控制字节,因此也被排除以确保兼容性和稳定性。

3、GBK如何兼容GB2312

GB2312编码表区号和位号都是十进制,而且需要同时+160,而GBK则规则简单一些,直接就是十六进制的区号加位号即可,下面我们从GBK的编码表中找下'侃'字,如下也是0xD9A9,这也就说明了GBK是兼容GB2312

四、Unicode(字符集)

Unicode是1991年一种国际标准字符集,旨在为全球所有语言的每个字符分配一个唯一的编码(称为码点),解决不同字符集间的兼容性问题。

解决的根本问题

  • 在Unicode出现之前,存在数百种不同的、互不兼容的字符编码(如ASCII、ISO-8859系列、GB2312/GBK、Big5、Shift-JIS等)
  • 这导致了严重的混乱:同一个数字在不同编码中可能代表完全不同的字符;文本在不同系统间交换时经常出现乱码;多语言文本共存非常困难

核心设计原则

  • 通用性: 包含所有现代及许多历史书写系统的字符,以及大量符号(数学、技术、货币、标点、表情符号等)
  • 唯一性: 每个字符(或可组合字符的一部分)都被分配一个唯一的码点。这个码点是一个数字(通常表示为U+XXXX,其中XXXX是4-6位的十六进制数)
    • U+0041 = 拉丁大写字母 'A'
    • U+4E2D = 汉字 '中'
    • U+1F600 = 笑脸表情符号 😀
  • 无歧义: 一个码点永远只对应一个字符(语义上),反之亦然(理想情况下)

编码空间与平面

  • Unicode的理论编码空间是21位(从U+0000U+10FFFF),总计超过100万个可能的码点
  • 这个空间被划分为17个平面,每个平面包含65,536(2^16)个码点
  • 基本多语言平面BMP是最重要的,包含了世界上最常用的字符(U+0000到U+FFFF)
  • 其他平面用于辅助文字、历史文字、特殊符号、私人使用区等

Unicode的实现:编码形式

  • Unicode字符集定义了字符码点映射关系,但它本身不规定字符在计算机中的存储方式(即编码方案)
  • 常见编码包括:
    • UTF-8:最常用;可变长度(1--4 字节);兼容 ASCII;在互联网上使用最广泛
    • UTF-16:可变长度(2 或 4 字节);Windows 系统常用
    • UTF-32:固定长度(4 字节);适合需要快速随机访问的系统

五、UTF-32、UTF-16(字符编码)

1、UTF-32编码方式

  • UTF-32是一种固定长度的Unicode编码方案,每个字符始终使用32位(4字节)表示
  • 编码方式:直接将Unicode字符的码点转换为32位二进制整数存储
    • 字符"A"(U+0041)的UTF-32编码为0x00000041
    • 汉字"啊"(U+554A)的UTF-32编码为0x0000554A
  • 码点范围:覆盖Unicode全部码点(U+0000至U+10FFFF),实际仅需21位,高位补0

2、UTF-16编码方式

  • UTF-16是一种变长的Unicode字符编码方式,它使用2字节或4字节来表示一个字符
  • 对于位于基本多语言平面BMP(U+0000-U+FFFF)的字符,UTF-16使用一个16位的代码单元来表示
    • 字符"A"(U+0041)的UTF-16编码为0041
    • 字符"你"(U+4F60)的UTF-16编码为4F60
  • 对于位于辅助平面(U+10000-U+10FFFF)的字符,UTF-16需要使用两个16位的代码单元(称为代理对)来表示
    • 假设计算Unicode码点U+1F60A(😊表情符号)对应的代理对
    • 将Unicode码点减去0x10000(0x1F60A - 0x10000 = 0xF60A)
    • 将计算结果0xF60A转为二进制20位,不够前面补0,分为两部分,高10位0x3D和低10位0x20A
    • 将高10位与0xD800相加,得到高位代理(0x3D + 0xD800 = 0xD83D)
    • 将低10位与0xDC00相加,得到低位代理(0x20A + 0xDC00 = 0xDE0A)
    • 最终 😊 = U+1F60A = 0xD83D 0xDE0A

3、字节顺序标记(BOM)

UTF-16 和 UTF-32 都是多字节编码(每个代码单元占用 2 或 4 个字节),因此在存储或传输时,字节顺序(大小端)至关重要。这就是字节顺序标记(BOM)存在的原因。

字节顺序

  • 大端(Big-Endian, BE):高位字节在前,低位字节在后(类似人类读书方式,先左后右)
    • 例如:字符 U+4E2D (中) 的 UTF-16BE 编码:4E 2D
  • 小端(Little-Endian, LE):低位字节在前,高位字节在后(就是大端的倒序)
    • 例如:字符 U+4E2D (中) 的 UTF-16LE 编码:2D 4E

字节顺序标记BOM

  • BOM(Byte Order Mark) 是一段特定的字节序列,出现在文本文件开头
  • 用于指示文件的字节顺序(大端序或小端序)
    • UTF-16大端BOM为0xFE 0xFF
    • UTF-16小端BOM为0xFF 0xFE
    • UTF-32大端BOM为0x00 0x00 0xFE 0xFF
    • UTF-32大端BOM为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

大小端作用对比

  • 大端注重"人类可读性"和标准化(通信、协议)
  • 小端注重"计算机效率"和实际处理便利(内存、CPU)

六、UTF-8(字符编码)

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
  • 码点 20013 属于 2048 ~ 65535 范围,编码之后需要用3字节存储
  • 将码点转换为二进制,20013 ---> 01001110 00101101(空缺位置用0填充,凑到8bit的整数倍)
  • 最终存储在计算机中的内容用3字节存储,其十六进制形式是0xE4 0xB8 0xAD
相关推荐
uzong3 小时前
技术故障复盘模版
后端
GetcharZp4 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程4 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研4 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi5 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国6 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy6 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack6 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9657 小时前
pip install 已经不再安全
后端
寻月隐君7 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github