ASCII 与字符编码表

0 到 255 每一个码位的十进制、十六进制、八进制、二进制和 HTML 实体,控制字符单独标出缩写的含义,128 到 159 这一段的 Latin-1 与 Windows-1252 两套定义分开对照。

显示 256 / 256 个码位|可打印 95 个、Latin-1 扩展 96 个、控制字符 65 个

使用说明

ASCII 是 7 位编码,只有 128 个码位,从 0 到 127。其中 0 到 31 是控制字符,原本用来控制电传打字机和打印机,像 NUL、BEL、HT、LF、CR、ESC 至今还在用;32 到 126 是可打印字符,也就是英文键盘上能直接敲出来的那批;127 是 DEL。Latin-1(ISO-8859-1)把 8 位填满到 256 个,低半段 0 到 127 与 ASCII 逐字节相同,高半段 128 到 255 补上了西欧语言的带重音字母、货币和度量符号。所以查前半段时,ASCII 表和 Latin-1 表的结论完全一致。

最需要记住的是 128 到 159 这一段的两套定义。ISO-8859-1 把它划成 C1 控制字符,什么也不画;微软的 Windows-1252 把这一段换成了弯引号、破折号、省略号、欧元符号等日常符号。同样一个字节 0x93,在 Latin-1 里是空的,在 cp1252 里是左双引号。很多「乱码」的根源就在这里:页面或接口声明用 latin-1,内容其实按 cp1252 编的,于是引号和破折号变成了问号或别的符号。表里把两套并排放出来,比对时一眼就能看出是这一段出的问题。

中文在这张表里查不到,这不是缺数据,而是 ASCII 本身表达不了中文。一个汉字在 GBK 里占两个字节、在 UTF-8 里通常占三个字节,每个字节的值都大于 127,早就超出了 ASCII 的定义范围。想把中文的字节看明白,得用十六进制转文本按字节对照,或者用编码检测与乱码修复去猜整段文本到底是用哪种编码存下来的。

UTF-8 的设计正好借用了这一点:0 到 127 的字符在 UTF-8 里仍然编成一个字节,且与 ASCII 完全相同,所以纯英文文本用 ASCII 和 UTF-8 存下来没有区别;大于 127 的字符要占两到四个字节,第一个字节的高位一定是 1。这样只认 ASCII 的老程序读到大于 127 的字节就能判断出这不是单个 ASCII 字符,不会把多字节字符拆散。这也是 UTF-8 能在老系统上逐步铺开的原因。想把某个字符在码点和转义序列之间来回看,用Unicode 转义;把这页提到的字节序列转成 Base64 存储,则用Base64 编解码。

最后是 HTML 实体。ASCII 段里只有 "、&、<、> 少数几个有命名实体,连单引号都没有标准命名写法;Latin-1 段的 160 到 255 反而大都有命名实体,比如  、©、×。命名实体可读性好但数量有限,数字实体永远可用(十进制 ©、十六进制 ©)。放在 HTML 或 XML 里写实体最稳妥,放到别的语言或纯文本里就直接写字符本身。控制字符没有字形,表里那列 ␀ 一类的符号只是 Unicode 提供的可见替代符号,方便在表格里占位,和真正的控制码不是一回事。

常见问题

ASCII 一共多少个字符?

128 个,从 0 到 127,因为它最初是 7 位编码。其中 0 到 31 是控制字符,32 到 126 是可打印字符,127 是 DEL。也就是说 ASCII 里既没有中文,也没有 e、a 这类带重音的西欧字母,它们都是后来由别的编码补进去的。

Latin-1 和 ASCII 是什么关系?

Latin-1(ISO-8859-1)是 8 位编码,低半段 0 到 127 与 ASCII 完全一致,高半段 128 到 255 用来放西欧的重音字母、货币和度量符号,把 256 个位置填满。所以它算 ASCII 的超集,而不是另一套互不相干的编码;前半部分查哪张表结果都一样。

为什么 128 到 159 这一段有两套完全不同的字符?

这是本页最值得留意的一段。ISO-8859-1 把 128 到 159 定义为 C1 控制字符,什么也画不出来;而微软的 Windows-1252(常被简称 cp1252)把这一段替换成了弯引号、破折号、省略号、欧元符号这些日常要用的符号。同一个字节 0x93,在 Latin-1 里是空的,在 cp1252 里是左双引号。网页声明用 latin-1、内容实际是 cp1252 时,这类乱码就出现了,表里两套定义都列出来方便对照。

中文能在这张表里查到吗?

查不到。这张表只覆盖 0 到 255,而中文一个字在 GBK 里占两个字节、在 UTF-8 里通常占三个字节,每个字节的值都大于 127,根本不在 ASCII 的定义里。所以用 ASCII 表是表达不了中文的,要处理中文得用十六进制转文本或编码检测修复这类工具按字节看。

UTF-8 和 ASCII 是什么关系?

UTF-8 是变长编码:0 到 127 的字符编码成一个字节,并且和 ASCII 的写法一模一样,所以纯英文文本用 ASCII 存还是用 UTF-8 存,结果完全相同;大于 127 的字符要占两到四个字节,而且第一个字节的高位一定是 1。这样一来,只认 ASCII 的老程序读到一个大于 127 的字节,就知道它后面还有续接字节,不会把多字节字符拆散。

命名实体和数字实体该用哪个?

命名实体(&copy;、&nbsp; 这类)可读性好,但 HTML5 里总共只有约 2200 个,而且 ASCII 段里只有 &quot;、&amp;、&lt;、&gt; 少数几个有名字,连单引号都没有标准的命名实体。数字实体永远可用,十进制写成 &#169;、十六进制写成 &#xA9;。放在 HTML 或 XML 里用实体最稳,放到别的语言、纯文本或聊天框里直接写字符本身更合适。

为什么 0 和 127 显示成 ␀、␡ 这种奇怪的符号?

因为这些码位本身不画任何东西,是控制码。表里用的 ␀ 和 ␡ 是 Unicode 专门为控制字符准备的可见替代符号(U+2400 到 U+2421),借来只是为了让表格看得见,它并不等于原字符。真要复制,复制走的仍然是那个真正的控制码,粘到编辑器里多半看不见,还会影响排版。

表里的数字格子点了会复制什么?

十进制、十六进制、八进制、二进制四格都能点,点了就复制该格显示的写法(带 0x、0o 前缀)。字符那一列点一下就复制字符本身。控制字符没有字形,点「字符」复制到的是真正的控制码,请留意它可能不可见。

相关:十六进制转文本Unicode 转义编码检测与乱码修复