大学计算机第三课

1.字符型数据在计算机内的表示

  (1)ASCII码

  ASCII码一共规定了128个字符的编码,比如空格"SPACE"是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

  (2)非ASCII编码

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

  然而不同的国家有不同的字母,即使都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表示的符号是一样的,不一样的只是128--255的这一段。

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

  虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。

  (3)Unicode编码

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

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

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

  Note:Unicode对象并没有编码。它们使用Unicode,一个一致的,通用的字符编码集。 当你在Python中处理Unicode对象的时候,你可以直接将它们混合使用和互相匹配而不必去考虑编码细节。

  Unicode编码系统为表达任意语言的任意字符而设计。它使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph)。每个数字代表唯一的至少在某种语言中使用的符号。(并不是所有的数字都用上了,但是总数已经超过了65535,所以2个字节的数字是不够用的。)被几种语言共用的字符通常使用相同的数字来编码,除非存在一个在理的语源学(etymological)理由使不这样做。不考虑这种情况的话,每个字符对应一个数字,每个数字对应一个字符。即不存在二义性。不再需要记录模式了。U+0041总是代表"A",即使这种语言没有"A"这个字符。

  初次面对这个创想,它看起来似乎很伟大。一种编码方式即可解决所有问题。文档可包含多种语言。不再需要在各种编码方式之间进行模式转换。但是很快,一个明显的问题跳到我们面前。4个字节?只为了单独一个字符 这似乎太浪费了,特别是对像英语和西语这样的语言,他们只需要不到1个字节即可以表达所需的字符。事实上,对于以象形为基础的语言(比如中文)这种方法也有浪费,因为这些语言的字符也从来不需要超过2个字节即可表达。

  有一种Unicode编码方式每1个字符使用4个字节。它叫做UTF-32,因为32位 = 4字节。UTF-32是一种直观的编码方式;它收录每一个Unicode字符(4字节数字)然后就以那个数字代表该字符。这种方法有其优点,最重要的一点就是可以在常数时间内定位字符串里的第N个字符,因为第N个字符从第4×Nth个字节开始。另外,它也有其缺点,最明显的就是它使用4个诡异的字节来存储每个诡异的字符…

  尽管有Unicode字符非常多,但是实际上大多数人不会用到超过前65535个以外的字符。因此,就有了另外一种Unicode编码方式,叫做UTF-16(因为16位 = 2字节)。UTF-16将0–65535范围内的字符编码成2个字节,如果真的需要表达那些很少使用的星芒层(astral plane)内超过这65535范围的Unicode字符,则需要使用一些诡异的技巧来实现。UTF-16编码最明显的优点是它在空间效率上比UTF-32高两倍,因为每个字符只需要2个字节来存储(除去65535范围以外的),而不是UTF-32中的4个字节。并且,如果我们假设某个字符串不包含任何星芒层中的字符,那么我们依然可以在常数时间内找到其中的第N个字符,直到它不成立为止这总是一个不错的推断…

  但是对于UTF-32和UTF-16编码方式还有一些其他不明显的缺点。不同的计算机系统会以不同的顺序保存字节。这意味着字符U+4E2D在UTF-16编码方式下可能被保存为4E 2D或者2D 4E,这取决于该系统使用的是大尾端(big-endian)还是小尾端(little-endian)。(对于UTF-32编码方式,则有更多种可能的字节排列。)只要文档没有离开你的计算机,它还是安全的 -- 同一台电脑上的不同程序使用相同的字节顺序(byte order)。但是当我们需要在系统之间传输这个文档的时候,也许在万维网中,我们就需要一种方法来指示当前我们的字节是怎样存储的。不然的话,接收文档的计算机就无法知道这两个字节4E 2D表达的到底是U+4E2D还是U+2D4E。

  为了解决这个问题,多字节的Unicode编码方式定义了一个字节顺序标记(Byte Order Mark),它是一个特殊的非打印字符,你可以把它包含在文档的开头来指示你所使用的字节顺序。对于UTF-16,字节顺序标记是U+FEFF。如果收到一个以字节FF FE开头的UTF-16编码的文档,你就能确定它的字节顺序是单向的(one way)的了;如果它以FE FF开头,则可以确定字节顺序反向了。

  不过,UTF-16还不够完美,特别是要处理许多ASCII字符时。如果仔细想想的话,甚至一个中文网页也会包含许多的ASCII字符 -- 所有包围在可打印中文字符周围的元素(element)和属性(attribute)。能够在常数时间内找到第Nth个字符当然非常好,但是依然存在着纠缠不休的星芒层字符的问题,这意味着你不能保证每个字符都是2个字节长,所以,除非你维护着另外一个索引,不然就不能真正意义上的在常数时间内定位第N个字符。另外,朋友,世界上肯定还存在很多的ASCII文本。

  Unicode的问题

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

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

  这里就有两个严重的问题

  第一个问题是,如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?

  第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果Unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

  它们造成的结果是:

  1)出现了Unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示Unicode。

  2)Unicode在很长一段时间内无法推广,直到互联网的出现。

  为了更好的理解,一般你可以认为unicode是没有编码的,只是一种表示;unicode进行encode编码后才成为utf-8, gbk等等,同时utf-8, gbk等等解码后就变成unicode。

   (4)UTF-8

  UTF-8是一种为Unicode设计的变长(variable-length)编码系统。即,不同的字符可使用不同数量的字节编码。对于ASCII字符(A-Z,&c.)UTF-8仅使用1个字节来编码。事实上,UTF-8中前128个字符(0–127)使用的是跟ASCII一样的编码方式。像ñ和ö这样的扩展拉丁字符(Extended Latin)则使用2个字节来编码。(这里的字节并不是像UTF-16中那样简单的Unicode编码点(unicode code point);它使用了一些位变换(bit-twiddling)。)中文字符比如则占用了3个字节。很少使用的星芒层字符则占用4个字节。

  缺点:因为每个字符使用不同数量的字节编码,所以寻找串中第N个字符是一个O(N)复杂度的操作 -- 即,串越长,则需要更多的时间来定位特定的字符。同时,还需要位变换来把字符编码成字节,把字节解码成字符。

  优点:在处理经常会用到的ASCII字符方面非常有效。在处理扩展的拉丁字符集方面也不比UTF-16差。对于中文字符来说,比UTF-32要好。同时,(在这一条上你得相信我,因为我不打算给你展示它的数学原理。)由位操作的天性使然,使用UTF-8不再存在字节顺序的问题了。一份以UTF-8编码的文档在不同的计算机之间是一样的比特流。

  互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种Unicode的实现方式。

  其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。UTF-8是Unicode的实现方式之一。

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

  UTF-8的编码规则

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

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

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

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

 

  (5)Unicode与UTF-8之间的转换

  通过上一节的例子,可以看到"严"的Unicode码是4E25{unicode表示是这么表示,对于全局可能不是最优的吧?},UTF-8编码是E4B8A5{unicode的一种比较优化的表示?},两者是不一样的。它们之间的转换可以通过程序实现。

  在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击"文件"菜单中的"另存为"命令,会跳出一个对话框,在最底部有一个"编码"的下拉条。

  里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。

  1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

  2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。

  3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。

  4)UTF-8编码,也就是上一节谈到的编码方法。

选择完"编码方式"后,点击"保存"按钮,文件的编码方式就立刻转换好了。

当然使用notepad++等更高级的文本编辑器转换更简单,自己可以试试。

   (6)GB2312

  1980年,中国制定了GB2312-80,一共收录了 7445 个字符,包括 6763 个汉字和 682 个其它符号。

  GB2312-80,简称为GB2312。

  在 Windows 中的代码页(Code Page)是 CP936。 

  (7)GBK

  微软,对GB2312-80的扩展,即利用GB 2312-80未使用的编码空间,收录所有的GB 13000.1-93和Unicode 1.1之中的汉字全部字符,制定了GBK编码。

  GBK 收录了 21886 个符号,它分为汉字区和图形符号区。汉字区包括 21003 个字符。

  GBK 作为对 GB2312 的扩展,在现在的 Windows 系统中仍然使用代码页 CP936 表示,但是同样的 936 的代码页跟一开始的 936 的代码页只支持 GB2312 编码不同,现在的 936 代码页支持 GBK 的编码,GBK 同时也向下兼容GB2312 编码。

  所以,技术编码上,GBK兼容旧的GB2312,但是编码方式和GB13000不同,不兼容GB13000,但是所包含文字上,算是和GB13000相同。

  技术编码方面上,演化顺序为:ASCII ⇒ GB2312 ⇒ GBK ⇒ GB18030

2.汉字编码

  (1)国标码

  6763个汉字,分两级:一级汉字有3755个,按拼音排列

  二级汉字有3008个,按偏旁部首排列

  为了编码,将汉字分成若干个区,每个区94个汉字,由区号和位号构成汉字的区位码。例如“中”位于54区48位,区位码为5448

  区号和位号加上32构成了汉字的国标码。国标码占两个字节。每个字节的最高位为0.

  (2)汉字机内码

  国标码的每个字节的最高位由0换1,即得到汉字的机内码

  ASCII码每个字节的最高位为0,所以西方的代码均小于128,而汉字机内码的每个字节都大于128,这样就可以将汉字编码与ASSCI码区分开。

  每个汉字编码占两个字节。

  (3)汉字的输入码

  这是一种用计算机标准键盘上的擦子键的不同排列组合来对汉字的输入进行的编码。

  如:区位码、全拼、双拼、五笔字形等。

  (4)汉字字形码

  汉字字形又称为字模,用于显示屏或打印机输出。通常有两各种表示方式:点阵和矢量函数表示。

3.音频数据

  计算机可以记录、存储和播放声音(如说话和音乐等).声音(也称为音频):是随时间连续变化的波。
  以波形形式记录声音,是一种模拟信号。为了数字化声音波形,每隔一定时间间隔对声音波形进行采样,并以数字数据的形式进行存储。数字化声音的质量由采样频率和采样点数据的测量精度(振幅值位数)以及声道有关。
  声音文件的扩展名: .wav .mid .mp3等。

4.图形和图像数据
  图形:指通过绘图软件绘制的由直线、圆、圆弧、任意曲线等组成的画面,图形文件中存放的是描述图形的指令,以矢量图形文件形式存贮。
  图像:指由数字照相机等输入的画面,数字化后以位图形式存贮。
  位图图像:由若干行和列的独立点(或称像素)组成的阵列,每个点的状态以二进制编码方式来存贮图像。如黑白图、灰度图、彩色图、真彩图。描述图的重要属性是分辨率和颜色深度。其扩展名为:.bmp, .pcx,.tif,.jpg,.gif
  矢量图形:由一串可重构图像的指令构成。其扩展名为:.wmf, .dxf, .mgx, .epx, .cgm

5.视频数据
  视频由一系列的图像组成。每一个图像是静止的,称之为帧。这些图可以被存为位图图像。将帧以一定的速度连续地显示在屏幕上,由于视觉暂留现象产生动态效果。所以视频是图像的动态形式。
  视频技术参数:帧速和数据量
  视频文件类型:影像文件(VCD)和流式视频文件(在线实况转播)

posted @ 2018-09-26 19:05  听风的人  阅读(344)  评论(0编辑  收藏  举报