计算机编码 -- Unicode && ASCII

计算机编码

Persus & Xie


字符集

计算机是以二进制的形式来存储数据的,它只认识01两个数字,我们在屏幕上看到的文字,在存储之前都被转换成了二进制,即01序列,在显示时也要根据二进制找到对应的字符。

在计算机中,每一个二进制位(bit)01两种状态;因此对于8个二进制位就可以组合出256种形状,这被称为一个字节(byte)。也就是说,一个字节可以用来表示256种不同的状态。每一个状态对应一个符号,也就是256个符号,从0000000011111111

可想而知,特定的文字必然对应这个特定的二进制序列,否则在转换过程中就会发很混乱。所以,就需要一套规范将文字和二进制对应起来,一套软件开发者和计算机公司都要遵守的规范。这样的一套规范称之为字符集 (Cahracter Set) 或者字符编码 (Character Encoding)。但是,严格地讲,字符集字符编码并不是一个概念,字符集定义了文字和二进制和对应关系,为每个字符分配了唯一编号。字符编码则规定了如何将文字的编号存储到计算机中。

字符集为每个字符分配了一个唯一的编号,类似于每个人都有一个身份证编号,通过编号就能找到对用的字符也可以将字符集理解为一个很大的表格,它列出了所有的字符和二进制序列的对应对应关系,计算机显示文字或者存储文字就是一个查表的过程。

在计算机发展的过程中,曾先后出现了几十上百种的字符集,至今有些仍在使用,但是有些却因为某些原因消亡了。

计算机诞生于美国,所以在研发它的过程中,一个需要考虑的问题是:如何将二进制和英文字母对应起来。曾经,各个公司和研发机构都有自己的编码规则,这些编码规则并不统一。

比如,IBM发明的EBCDIC编码;中国制定了GB2312编码规则,用以编译中文;日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里。

本文主要讲述的是一门专门针对英文的字符集ASCII编码,以及全球统一的编码**UTF-8编码**。

ASCII 编码

ASCII 是American Standard Code for Information Interchange的缩写,翻译过来是“美国信息交换标准代码”。ASCII 的标准版本于 1967 年第一次发布,最后一次更新则是在 1986 年,迄今为止共收录了 128 个字符,包含了基本的拉丁字母(英文字母)、阿拉伯数字(也就是 1234567890)、标点符号(,.!等)、特殊符号(@#$%^&*等)以及一些具有控制功能的字符所谓ASCII码,就是将英文字母和常用符号用特定的数字去表达。 比如:

字母A用ASCII编码是十进制的65,二进制的01000001

字符0用ASCII编码是十进制的48,二进制的00110000,注意字符'0'和整数0是不同的;

我们可以将ASCII编码理解为一个英汉字典,中文代表128个字符,英文代表计算机中所对应的二进制序列。这种形式让计算机和人类的交互变得更便捷。在 ASCII 编码中,大写字母、小写字母和阿拉伯数字都是连续分布的(见下表),这给程序设计带来了很大的方便。例如要判断一个字符是否是大写字母,就可以判断该字符的 ASCII 编码值是否在 65~90 的范围内。

将ASCII 可显示字符转换为十六进制或者二进制

在制订ASCII编码的过程中,首先是对128个字符用以十进制从0~127排序,每个字符对应着指定的十进制数字,如果要用其中某个字符转换为二进制或者16进制,是将其对应的十进制数字转换为二进制或者十六进制;举例如下:

在ASCII编码表中,字符Q所对应的十进制数字为81,那么将整数81转换为二进制或者十六进制,结果就是字符Q所对应的二进制或者十六进制序列。

转十六进制的过程图如下:十进制转81到十六进制为51

在这里插入图片描述

转二进制的过程图如下:十进制数字81转十六进制为1010001

在这里插入图片描述

ASCII 编码表

标准 ASCII 编码共收录了 128 个字符,其中包含了 33 个控制字符和 95 个可显示字符:

ASCII编码--控制字符
二进制十进制十六进制字符/缩写解释
00000000000NUL (NULL)空字符
00000001101SOH (Start Of Headling)标题开始
00000010202STX (Start Of Text)正文开始
00000011303ETX (End Of Text)正文结束
00000100404EOT (End Of Transmission)传输结束
00000101505ENQ (Enquiry)请求
00000110606ACK (Acknowledge)回应/响应/收到通知
00000111707BEL (Bell)响铃
00001000808BS (Backspace)退格
00001001909HT (Horizontal Tab)水平制表符
00001010100ALF/NL(Line Feed/New Line)换行键
00001011110BVT (Vertical Tab)垂直制表符
00001100120CFF/NP (Form Feed/New Page)换页键
00001101130DCR (Carriage Return)回车键
00001110140ESO (Shift Out)不用切换
00001111150FSI (Shift In)启用切换
000100001610DLE (Data Link Escape)数据链路转义
000100011711DC1/XON (Device Control 1/Transmission On)设备控制1/传输开始
000100101812DC2 (Device Control 2)设备控制2
000100111913DC3/XOFF (Device Control 3/Transmission Off)设备控制3/传输中断
000101002014DC4 (Device Control 4)设备控制4
000101012115NAK (Negative Acknowledge)无响应/非正常响应/拒绝接收
000101102216SYN (Synchronous Idle)同步空闲
000101112317ETB (End of Transmission Block)传输块结束/块传输终止
000110002418CAN (Cancel)取消
000110012519EM (End of Medium)已到介质末端/介质存储已满/介质中断
00011010261ASUB (Substitute)替补/替换
00011011271BESC (Escape)逃离/取消
00011100281CFS (File Separator)文件分割符
00011101291DGS (Group Separator)组分隔符/分组符
00011110301ERS (Record Separator)记录分离符
00011111311FUS (Unit Separator)单元分隔符
011111111277FDEL (Delete)删除
ASCII编码--可显示字符
二进制十进制十六进制字符/解释
001000003220(Space)/空格
001000013321!
001000103422"
001000113523#
001001003624$
001001013725%
001001103826&
001001113927
001010004028(
001010014129)
00101010422A*
00101011432B+
00101100442C,
00101101452D-
00101110462E.
00101111472F/
0011000048300
0011000149311
0011001050322
0011001151333
0011010052344
0011010153355
0011011054366
0011011155377
0011100056388
0011100157399
00111010583A:
00111011593B;
00111100603C<
00111101613D=
00111110623E>
00111111633F?
010000006440@
010000016541A
010000106642B
010000116743C
010001006844D
010001016945E
010001107046F
010001117147G
010010007248H
010010017349I
01001010744AJ
01001011754BK
01001100764CL
01001101774DM
01001110784EN
01001111794FO
010100008050P
010100018151Q
010100108252R
010100118353S
010101008454T
010101018555U
010101108656V
010101118757W
010110008858X
010110018959Y
01011010905AZ
01011011915B[
01011100925C\
01011101935D]
01011110945E^
01011111955F_
011000009660`
011000019761a
011000109862b
011000119963c
0110010010064d
0110010110165e
0110011010266f
0110011110367g
0110100010468h
0110100110569i
011010101066Aj
011010111076Bk
011011001086Cl
011011011096Dm
011011101106En
011011111116Fo
0111000011270p
0111000111371q
0111001011472r
0111001111573s
0111010011674t
0111010111775u
0111011011876v
0111011111977w
0111100012078x
0111100112179y
011110101227Az
011110111237B{
011111001247C|
011111011257D}
011111101267E~

上表列出的是标准的 ASCII 编码,它共收录了 128 个字符,用一个字节中较低的 7 个比特位(bit)足以表示( 2 7 2^7 27 = 128),所以还会空闲下一个比特位,所以有一个比特位被闲置。

非ASCII编码

以英语为母语国家用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母é上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样的话,这些欧洲国家使用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0–127表示的符号是一样的,不一样的只是128–255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。

中文编码的问题需要专文讨论,这篇文章不作分析。这里只指出,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。

Unicode

世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么不同系统在打开同一个文件常常出现乱码?就是因为两个系统使用的编码方式不一样。

假设,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母AU+4E25表示汉字。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

Unicode 的问题

需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字的unicode是十六进制数4E25,转换成二进制数足足有15位100111000100101,也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节(byte)或者4个字节(byte),甚至更多。

y因此会出现两个严重的问题,第一个问题是,如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果Unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:

  • 出现了Unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示Unicode。
  • Unicode在很长一段时间内无法推广,直到互联网的出现。

UTF-8

互联网的普及,急需一种统一的编码方式。UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其他实现方式还包括UTF-16(字符用两个byte或四个byte表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

  • 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字符x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------±--------------------------------------------
0000 0000-0000 007F | 0xxxxxxx >>>>>>> 1个字节
0000 0080-0000 07FF | 110xxxxx 10xxxxxx >>>>>>> 2个字节
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx >>>>>>> 3个字节
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx >>>>>>> 4个字节

下面,还是以汉字"严"为例,演示如何实现UTF-8编码。

已知的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此UTF-8编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,UTF-8编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5

总结

本文是在写程序处理数据,在对数据进行编码的过程中遇到一系列问题,所以在本篇中作出梳理。本文主要涉及到编码的认识,编码的过程,ASCII编码,Unicode编码。

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页