计算机字符编码入门篇

前言

本文旨在为初学者提供有关计算机字符编码的基础知识,以帮助他们初步理解计算机中字符编码的概念。鉴于我个人知识的限制,如有不准确之处,欢迎指正并提供建议。

文中部分内容参考ChatGPT,在此感谢ppword的大力支持。

一、什么是二进制

二进制是一种数字表示系统,它只使用两个数字:0和1。与十进制不同,它使用基数2,这意味着每个位置的数字的权值都是2的幂。在二进制中,数字的每一位表示一种状态,通常用于计算机内部的数据表示和处理。

以下是一些二进制数字示例以及它们在十进制中的对应值:

  • 二进制的0和1分别表示十进制的0和1。
  • 0(二进制)表示0(十进制)
  • 1 (二进制)表示1(十进制),加1后。
  • 10(二进制)表示2(十进制),这是因为在二进制中,当某一位达到1后,它会进位到下一位。
  • 11(二进制)表示3(十进制),再加1后。
  • 100(二进制)表示4(十进制),再次进位,依次类推。

简而言之,二进制是一种由0和1组成的数字系统,通过排列不同位置上的0和1来表示各种数字。这种系统在计算机内部非常常见,因为计算机使用开关状态来处理信息,其中0表示关闭或低电平,1表示打开或高电平,因此很适合用二进制来表示和操作数据。

二、为什么计算机采用二进制来表示数据

计算机采用了二进制来表示数据,主要是因为电子计算机的内部元件(例如晶体管和电路)可以轻松地表示和处理两种状态,即开和关,或者电平高和电平低。这些元件的工作方式使得二进制非常适合作为计算机的内部数据表示方法的几个原因:

  • 电子开关:计算机内部使用的主要元件是电子开关,这些开关只有两种状态,打开和关闭。这与二进制的两个值(0和1)非常契合,因此计算机可以用非常简单的方式来表示和处理数据。

  • 稳定性和可靠性:二进制状态更稳定,容易维护和判断。由于电子元件的物理特性,它们能够可靠地保持在开或关的状态,减少了数据传输和存储中的误差。

  • 逻辑简单性:二进制非常适合逻辑运算。计算机中的许多操作都涉及到逻辑运算,例如AND、OR、NOT等。这些运算在二进制中非常直观和容易实现。

现在我们知道了,计算进它只能表示一堆由0或1组成的东西,那我们的“a、b、c、d”怎么办,它能表示的了么?

三、计算机怎么样表示文本

这时,我们的大美丽同学就跳出来说,这个还不简单,我们只要给每一个我们要用到的字符,分别给它们分配一个固定的0和1的组合体,以后大家都按这个标准来,不就解决了么。

她很快就给制作出来了这么一个对应规则。

1、ASCII码

这就是大名鼎鼎的ASCII码表

二进制(Bin) 十进制(Dec) 十六进制(Hex) 缩写/字符 解释
0000 0000 0 0x00 NUL(null) 空字符
0000 0001 1 0x01 SOH(start of headline) 标题开始
0000 0010 2 0x02 STX (start of text) 正文开始
0000 0011 3 0x03 ETX (end of text) 正文结束
0000 0100 4 0x04 EOT (end of transmission) 传输结束
0000 0101 5 0x05 ENQ (enquiry) 请求
0000 0110 6 0x06 ACK (acknowledge) 收到通知
0000 0111 7 0x07 BEL (bell) 响铃
0000 1000 8 0x08 BS (backspace) 退格
0000 1001 9 0x09 HT (horizontal tab) 水平制表符
0000 1010 10 0x0A LF (NL line feed, new line) 换行键
0000 1011 11 0x0B VT (vertical tab) 垂直制表符
0000 1100 12 0x0C FF (NP form feed, new page) 换页键
0000 1101 13 0x0D CR (carriage return) 回车键
0000 1110 14 0x0E SO (shift out) 不用切换
0000 1111 15 0x0F SI (shift in) 启用切换
0001 0000 16 0x10 DLE (data link escape) 数据链路转义
0001 0001 17 0x11 DC1 (device control 1) 设备控制1
0001 0010 18 0x12 DC2 (device control 2) 设备控制2
0001 0011 19 0x13 DC3 (device control 3) 设备控制3
0001 0100 20 0x14 DC4 (device control 4) 设备控制4
0001 0101 21 0x15 NAK (negative acknowledge) 拒绝接收
0001 0110 22 0x16 SYN (synchronous idle) 同步空闲
0001 0111 23 0x17 ETB (end of trans. block) 结束传输块
0001 1000 24 0x18 CAN (cancel) 取消
0001 1001 25 0x19 EM (end of medium) 媒介结束
0001 1010 26 0x1A SUB (substitute) 代替
0001 1011 27 0x1B ESC (escape) 换码(溢出)
0001 1100 28 0x1C FS (file separator) 文件分隔符
0001 1101 29 0x1D GS (group separator) 分组符
0001 1110 30 0x1E RS (record separator) 记录分隔符
0001 1111 31 0x1F US (unit separator) 单元分隔符
0010 0000 32 0x20 (space) 空格
0010 0001 33 0x21 ! 叹号
0010 0010 34 0x22 " 双引号
0010 0011 35 0x23 # 井号
0010 0100 36 0x24 $ 美元符
0010 0101 37 0x25 % 百分号
0010 0110 38 0x26 & 和号
0010 0111 39 0x27 ' 闭单引号
0010 1000 40 0x28 ( 开括号
0010 1001 41 0x29 ) 闭括号
0010 1010 42 0x2A * 星号
0010 1011 43 0x2B + 加号
0010 1100 44 0x2C , 逗号
0010 1101 45 0x2D - 减号/破折号
0010 1110 46 0x2E . 句号
0010 1111 47 0x2F / 斜杠
0011 0000 48 0x30 0 字符0
0011 0001 49 0x31 1 字符1
0011 0010 50 0x32 2 字符2
0011 0011 51 0x33 3 字符3
0011 0100 52 0x34 4 字符4
0011 0101 53 0x35 5 字符5
0011 0110 54 0x36 6 字符6
0011 0111 55 0x37 7 字符7
0011 1000 56 0x38 8 字符8
0011 1001 57 0x39 9 字符9
0011 1010 58 0x3A : 冒号
0011 1011 59 0x3B ; 分号
0011 1100 60 0x3C < 小于
0011 1101 61 0x3D = 等号
0011 1110 62 0x3E > 大于
0011 1111 63 0x3F ? 问号
0100 0000 64 0x40 @ 电子邮件符号
0100 0001 65 0x41 A 大写字母A
0100 0010 66 0x42 B 大写字母B
0100 0011 67 0x43 C 大写字母C
0100 0100 68 0x44 D 大写字母D
0100 0101 69 0x45 E 大写字母E
0100 0110 70 0x46 F 大写字母F
0100 0111 71 0x47 G 大写字母G
0100 1000 72 0x48 H 大写字母H
0100 1001 73 0x49 I 大写字母I
01001010 74 0x4A J 大写字母J
0100 1011 75 0x4B K 大写字母K
0100 1100 76 0x4C L 大写字母L
0100 1101 77 0x4D M 大写字母M
0100 1110 78 0x4E N 大写字母N
0100 1111 79 0x4F O 大写字母O
0101 0000 80 0x50 P 大写字母P
0101 0001 81 0x51 Q 大写字母Q
0101 0010 82 0x52 R 大写字母R
0101 0011 83 0x53 S 大写字母S
0101 0100 84 0x54 T 大写字母T
0101 0101 85 0x55 U 大写字母U
0101 0110 86 0x56 V 大写字母V
0101 0111 87 0x57 W 大写字母W
0101 1000 88 0x58 X 大写字母X
0101 1001 89 0x59 Y 大写字母Y
0101 1010 90 0x5A Z 大写字母Z
0101 1011 91 0x5B [ 开方括号
0101 1100 92 0x5C \ 反斜杠
0101 1101 93 0x5D ] 闭方括号
0101 1110 94 0x5E ^ 脱字符
0101 1111 95 0x5F _ 下划线
0110 0000 96 0x60 ` 开单引号
0110 0001 97 0x61 a 小写字母a
0110 0010 98 0x62 b 小写字母b
0110 0011 99 0x63 c 小写字母c
0110 0100 100 0x64 d 小写字母d
0110 0101 101 0x65 e 小写字母e
0110 0110 102 0x66 f 小写字母f
0110 0111 103 0x67 g 小写字母g
0110 1000 104 0x68 h 小写字母h
0110 1001 105 0x69 i 小写字母i
0110 1010 106 0x6A j 小写字母j
0110 1011 107 0x6B k 小写字母k
0110 1100 108 0x6C l 小写字母l
0110 1101 109 0x6D m 小写字母m
0110 1110 110 0x6E n 小写字母n
0110 1111 111 0x6F o 小写字母o
0111 0000 112 0x70 p 小写字母p
0111 0001 113 0x71 q 小写字母q
0111 0010 114 0x72 r 小写字母r
0111 0011 115 0x73 s 小写字母s
0111 0100 116 0x74 t 小写字母t
0111 0101 117 0x75 u 小写字母u
0111 0110 118 0x76 v 小写字母v
0111 0111 119 0x77 w 小写字母w
0111 1000 120 0x78 x 小写字母x
0111 1001 121 0x79 y 小写字母y
0111 1010 122 0x7A z 小写字母z
0111 1011 123 0x7B { 开花括号
0111 1100 124 0x7C | 垂线
0111 1101 125 0x7D } 闭花括号
0111 1110 126 0x7E ~ 波浪号
0111 1111 127 0x7F DEL (delete) 删除

好家伙,密密麻麻的,还真是什么都有。有些同学看了之后,不免以中就有一些疑惑了。

1)为什么这“二进制”那列,整整齐齐的都是8个0或1的组合?

当ASCII码被设计时,主要用途是在早期计算机和通信系统中传输文本字符。这种情况下,128个字符通常足够表示英语和一些其他常用语言的字符。因此,7位提供的字符范围正好足够。之所以写成8位,应该和“字节”有关,一个字节刚好是8位,在这里习惯性的把最高位补上0。

字节(byte)这个单位的起源可以追溯到早期计算机领域的发展历史。字节的定义和大小不是一开始就确定的,而是随着计算机技术的发展和标准化逐渐形成的。

以下是一些关于字节和为什么一字节通常被定义为8位的解释:

  • 早期计算机架构:早期计算机使用了各种不同的数据结构和字长(一个字长是指一个计算机可以一次处理的二进制位数)。在这个时期,字节的大小并不是一个统一的标准。不同的计算机系统使用了不同大小的字节,如6位、7位或9位。

  • 8位字节的普及:在计算机发展的早期阶段,一些计算机科学家和工程师开始推崇使用8位字节。这种设计选择有几个原因:

    • 8位字节提供了256个不同的组合,足够表示各种字符、数字、符号和控制字符,这对于字符编码来说是非常有用的。
    • 8位字节相对于其他大小的字节更容易在硬件上实现,因为它刚好是2的幂次方(2^3=8),这对于计算机设计来说更加简单和高效。
  • 标准化:随着时间的推移,8位字节逐渐成为一种标准,并在计算机领域广泛普及。这种标准化有助于确保不同计算机系统之间的兼容性,同时也简化了数据交换和编程。

2)为什么表中还有一些奇怪的字符,例如回车、换行、退格等?

这些控制字符用于控制打印机、终端和通信设备的行为。这些字符不是可打印字符,但在通信和控制领域中非常重要。

3)按前面所说,“0000 0001”应该是表示1,那这表里的怎么又变成“0011 0001”表示1了呢?

您的观察是正确的,二进制中的 "0000 0001" 表示的确实是数字 1,但这不同于 ASCII 码中表示数字字符 "1" 的方式。ASCII 码使用 7 位二进制编码字符,而 "0011 0001" 是表示字符 "1" 的 ASCII 编码值。
比如“0100 0001”,你把它当二进制的数字看,它就是65,把它当字符看,它就是“A”,反正就是全凭你一张嘴,咋说咋有理。

4)那一列“十六进制”又是什么鬼?

十六进制也是一种数字表示系统,它使用16个不同的字符来表示数据,包括0-9和A-F。
我们观察一下其中一个二进制数,如:0111 0001,如果都要这么写确实不方便,再来看一下它对应的十六进制值:0x71(数字前带0x的都是十六进制),这样就好读也更方便书写。
从这不难看出,前面的四位0111刚好是0x7,后面的是0x1,四位的二进制刚好转换成1位的十六进制(2^4=16)。

所以选择使用十六进制的原因有:

  • 紧凑性:十六进制表示方式比二进制更紧凑。在十六进制中,一个数字可以表示4个二进制位。这使得在处理和表示大量二进制数据时,十六进制更容易阅读和管理。特别是在编程和计算机内部数据处理方面,使用十六进制可以提高可读性。

  • 易于转换:十六进制和二进制之间的转换非常容易。每个十六进制数字对应于4个二进制位,因此可以很容易地将十六进制数转换为二进制,反之亦然。这使得在编程和计算机领域中,可以轻松地在二进制和十六进制之间切换,以便于调试和数据处理。

5)那ASCII编码这么好,难道就没什么问题么?

  • ASCII编码只使用7位二进制来表示字符,因此只能表示128个不同的字符。这足够用来表示英文字母、数字和一些基本符号,但对于其他语言的字符或特殊符号来说,就不够了。这对于国际化的计算机应用来说是一个巨大的问题,因为不同国家和地区使用不同的字符集。

为了解决ASCII编码的局限性,Unicode应运而生。

2、Unicode字符编码标准

Unicode(统一码)是一个国际标准,是一种字符编码标准,用于表示世界上几乎所有已知的书写系统的字符和符号。它的主要目的是为了解决不同字符编码标准之间的兼容性问题,确保文本在不同计算机系统、操作系统和编程语言之间能够正确地显示和交换。

在 Unicode 中,每个字符都被分配一个唯一的数字代码点,这个代码点可以用来表示该字符。Unicode 编码包括了各种语言中的字母、数字、标点符号、符号、特殊字符和控制字符等。它涵盖了世界上许多不同的语言,包括英语、中文、日语、阿拉伯语、希伯来语、俄语等等。

代码点(Code Points): Unicode 中的每个字符都被分配一个唯一的代码点,这是一个用来标识字符的整数值。这个代码点通常以 U+ 开头,后面跟随一个表示十六进制数的数字,例如 U+0041 表示拉丁字母 "A"。Unicode 定义了一个代码点范围,从 U+0000 到 U+10FFFF。

  • 那如此多的代码点,又是怎么划分区域(平面)的,每个区域又分别表示什么样的字符,看下图:
平面 码点范围 平面名称 描述
0 U+0000 - U+FFFF 基本多文种平面(Basic Multilingual Plane) 包含了大部分常用字符,如拉丁字母、希腊字母、标点符号、数字、常见汉字
1 U+010000 - U+01FFFF 增补多文种平面-A(SMP-A) 包括一些不常用的字符和古代文字,如伊斯兰文、埃及象形文字等
2 U+020000 - U+02FFFF 增补多文种平面-B(SMP-B) 用于容纳更多的稀有和历史字符,如饰字符和表意字符描述
3 U+030000 - U+03FFFF 增补多文种平面-C(SMP-C) 包括更多的字符,如尼亚文字、埃及草书等
4 U+040000 - U+04FFFF 增补多文种平面-D(SMP-D) 包括一些亚洲文字、修饰符和 Emoji 表情符号
5 U+050000 - U+05FFFF 增补多文种平面-E(SMP-E) 包含一些其他语言的字符,如摩尔斯电码、装饰符等
6 U+060000 - U+06FFFF 增补多文种平面-F(SMP-F) 主要用于扩展埃及象形文字,包括更多的字符和修饰符
7 U+070000 - U+07FFFF 增补多文种平面-G(SMP-G) 用于收容带有特殊符号和修饰符的文字,如印度的许多脚本
8 U+080000 - U+08FFFF 增补多文种平面-H(SMP-H) 包括少数民族文字、修饰符、数字和特殊符号
9 U+090000 - U+09FFFF 增补多文种平面-I(SMP-I) 主要用于扩展已存在的字符集
10 U+0A0000 - U+0AFFFF 增补多文种平面-J(SMP-J) 继续扩展已有字符集,包括一些汉字和其他字符
11 U+0B0000 - U+0BFFFF 增补多文种平面-K(SMP-K) 用于存放汉字的变体和历史汉字
12 U+0C0000 - U+0CFFFF 增补多文种平面-L(SMP-L) 主要包括中世纪的拉丁文字、特殊符号和 Emoji 扩展
13 U+0D0000 - U+0DFFFF 增补多文种平面-M(SMP-M) 包含修饰符、音符和 Emoji 扩展
14 U+0E0000 - U+0EFFFF 增补多文种平面-N(SMP-N) 包括 Emoji 扩展,如符号、动物和食物
15 U+0F0000 - U+0FFFFF 增补多文种平面-O(SMP-O) 用于 Emoji 扩展,包括情感符号和其他特殊符号
16 U+100000 - U+10FFFF 增补多文种平面-P(SMP-P) 用于存放一些音乐符号和 Emoji 扩展

常用字符Unicode编码范围:

字符类型 码点范围
汉字 U+4e00 - U+9fa5 十进制[19968 - 40869]
数字 U+0030 - U+0039 十进制[48 - 57]
小写字母 U+0061 - U+007a 十进制[97 - 122]
大写字母 U+0041 - U+005a 十进制[65 - 90])

标准定好了,这下万事大吉了,不管什么字符,总能够有办法表示出来了,如果再有新的字符,大不了再多定义几个平面,码点多放几个字节就搞定了。

那标准有了,又要怎么使用呢?

3、Unicode 字符编码方案

1)UTF-16

UTF-16 使用16位(2字节)来编码这些字符,因此它足够表示 BMP 中的字符,但对于 BMP 之外的字符,UTF-16 需要使用额外的机制来处理。
最早出现的 UTF-16 并不是为了表示所有的 Unicode 字符,而是为了表示 Unicode 基本多文种平面(Basic Multilingual Plane,BMP)中的字符。BMP 包含了大多数常用的字符,包括拉丁字母、数字、标点符号、常见汉字等等。

特点:
  • 兼容性: UTF-16 具有与 ASCII 和基本多文种平面(BMP)兼容的特点。ASCII 字符在 UTF-16 中使用单个16位编码表示,这使得 UTF-16 可以无缝处理包含 ASCII 字符的文本。

  • 变长编码: UTF-16 是一种变长编码,大多数常用字符和 BMP 中的字符使用2个字节表示,而增补多文种平面(SMP)中的字符使用4个字节表示。这种设计在某些情况下可以节省存储空间,但也意味着编码单元的大小不固定。

  • 支持大多数字符: UTF-16 能够表示大多数 Unicode 字符,包括各种语言的字符、符号和特殊符号。

不足:
  • 变长编码: UTF-16 的变长编码特性意味着字符的编码单元大小不固定,这可能导致处理文本数据时的复杂性。对于 SMP 中的字符,需要额外的编码单元(代理对),这增加了处理的复杂性。

  • 字节序问题: UTF-16 存在字节序问题,即字节序(Big Endian 或 Little Endian)可能影响文本的正确解释。这可能导致在不同系统之间或在网络传输中出现问题。

  • 不适用于某些字符: 尽管 UTF-16 能够表示大多数字符,但仍然有一些字符,特别是一些辅助语言和古代文字字符,无法直接表示,需要使用组合或其他机制。

从上面不难看出,使用UTF-16的时候,不管表示什么字符,至少需要2个字节。那对于那些原本只要一个字节就能表示出来的字符来说,不管是在存储还是网络传输的时候都有不少的浪费,所以就出现了UTF-8。

2)UTF-8

UTF-8 是一种变长编码,它可以使用1到4个字节来表示不同的 Unicode 码点。对于大多数常用的字符,UTF-8 使用1到3个字节,只有少数罕见字符需要4个字节。这种编码方式节省了存储空间,并且适合在互联网和计算机系统中广泛使用。

UTF-8 的编码规则如下:
  • 对于单字节的字符,字节的第一位设为 0,后面 7 位为其代码点。
  • 对于 n 字节的符号( n > 1),第一个字节的前 n 位都设为 1,第 n + 1 位设为 0,后面字节的前两位一律设为 10 。剩下的没有提及的二进制位,全部为为其代码点。
码点范围(十六进制) UTF-8编码(二进制)
U+00 - U+7F 0xxxxxxx
U+0080 - U+07FF 110xxxxx 10xxxxxx
U+0800 - U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
U+010000 - U+10 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

转换时,填充空位,从低位(右)至高位(左),高位上多余的0直接丢弃

  • 示例
字符 码点 码点二进制 UTF-8编码(二进制) UTF-8编码(十六进制)
A U+41 (0)1000001 (0)1000001 0x41
π U+03c0 (00000)011 11000000 (110)01111 (10)000000 0xCF80
😀 U+1F642 (000)00001 11110110 01000010 (11110)000 (10)011111 (10)011001 (10)000010 0xF09F9892
特点:
  • 兼容性: UTF-8 兼容 ASCII,这意味着任何有效的 ASCII 文本都是有效的 UTF-8 文本。这种兼容性使得从 ASCII 过渡到 Unicode 变得无缝,并且已有的 ASCII 文本无需任何修改即可在 UTF-8 中使用。

  • 变长编码: UTF-8 是一种变长编码方案,可以使用1到4个字节来表示不同的 Unicode 码点。这使得 UTF-8 非常节省存储空间,因为常用字符通常只需要1到3个字节。

  • 全球支持: UTF-8 能够表示世界上几乎所有已知的语言的字符,包括拉丁字母、亚洲文字、希腊字母、西里尔字母、非洲字符等等。这使得 UTF-8 成为一种通用的字符编码方案,适用于全球范围内的文本处理。

  • 互联网标准: UTF-8 是互联网上最常用的字符编码方案之一,几乎所有的现代网络通信协议和网页内容都使用 UTF-8 来表示文本数据。这有助于实现全球化和多语言支持。

  • 适用性广泛: UTF-8 在各种操作系统、编程语言和应用程序中得到广泛支持,使得它成为开发者和用户的首选编码方案。

不足:
  • 不适合固定大小的数据结构: 由于 UTF-8 是变长编码,它不适合用于某些需要固定大小数据结构的场景,如数据库表的字段、二进制文件格式等。在这些情况下,UTF-32 或其他固定大小编码可能更合适。

  • 处理复杂字符需要额外计算: 对于 SMP(增补多文种平面)中的字符或 Emoji 表情符号,UTF-8 需要使用多个字节来表示,这可能需要额外的计算和处理,不如 UTF-32 那样直观。

  • 不适合随机访问: 由于 UTF-8 是变长编码,要在文本中进行随机访问(如查找第 n 个字符)需要遍历整个文本,而 UTF-32 更适合这种操作。

  • 编码和解码复杂性: UTF-8 的编码和解码算法相对复杂,需要额外的计算来确定字符的边界和编码单元的数量。这可能对某些性能敏感的应用产生一些开销。

3)UTF-32

UTF-32是Unicode字符集的一种完全统一的编码方案,每个字符都用32位(4字节)表示,这使得它可以容纳Unicode字符集中的任何字符。

特点:
  • 固定长度编码:UTF-32采用固定长度的编码,每个字符都用相同数量的字节表示。这样的编码方案使得在处理文本时更加简单和高效,因为不需要像变长编码(如UTF-8和UTF-16)那样在字符之间查找分隔符。

  • 简化文本处理:UTF-32编码在处理文本时具有一定的优势,特别是在需要快速随机访问字符的情况下。由于每个字符都占据相同数量的字节,可以轻松计算和索引字符的位置。

不足:
  • 占用更多存储空间:UTF-32通常占用比UTF-8和UTF-16更多的存储空间,特别是对于包含大量ASCII字符的文本。
  • 内存占用:对于大量文本数据,UTF-32需要更多的内存,可能不适用于内存受限的环境。
  • 不适合网络传输:UTF-32的固定长度编码会增加网络传输的数据量。

结束

当然,除了上述提到的字符编码方案,世界上还存在着众多其他编码标准,涵盖了各种语言和地区的需求。例如,中文有GB2312、GBK、GB18030、Big5等多种编码方案,而Latin-1等字符编码则是一种局限于特定语言或地区的标准。有机会我们将继续探讨这些编码标准,以便更好地理解它们的起源、应用和发展历程。感谢大家的支持与关注!

热门相关:精灵掌门人   名门盛婚:首席,别来无恙!   紫府仙缘   妖精美人馆   重生成偏执霍少的小仙女