当前位置:   article > 正文

ASCII、Unicode、UCS-2、UTF-8 等字符编码规则的区别与联系

ucs-2



一、前言

  刚刚查询完ASCII码后,突然想搞清楚字符的编码。
  计算机对数据的读取是按照一个字节的大小来读取识别的,那么面对全世界这么多语言,计算机怎么知道是多个字节表示一个符号,而不是分别表示多个符号呢?
  结合了几篇前辈的文章,自己重新总结了下ASCII、Unicode、UTF-8的编码规则。



二、补充(bit & Byte)

  在计算机中所有信息都是以二进制位01来存储的。

  8个比特位是一个字节(8 bit = 1 Byte),即一个字节一共可以用来表示256种不同的状态。



三、ASCII(美国信息交换标准代码)

  ASCII(American Standard Code for Information Interchange):美国信息交换标准代码是基于拉丁字母的一套电脑编码系统,主要用于显示电脑和其他电信设备中的现代英语和其他西欧语言。

  电脑所有信息都是以二进制的方式来计算和存储的,那么人们能识别的文字和计算机中的二进制必然存在一种映射关系,ASCII就是最初的一种映射关系,也叫字符集。

  比如在ASCII中,大写字母“A”对应ASCII码的十进制是65,二进制就是0100 0001;小写字母a对应ASCII码的十进制是97(二进制0110 0001);阿拉伯数字0对应ASCII码的十进制是48(二进制0011 0000);还有空格320010 0000)等等一些键盘上所见的符号。

以大写字母A字符的标准ASCII码为例
01000001
ASCII标准码统一规定为00/10/10/10/10/10/10/1

ASCII中的所有字符与对应编码,请看我的上一篇文章:《ASCII美国信息交换标准代码表》



四、各国独立的语言编码

  随着计算机在全球的发展和普及开来,单字节只能够表示阿拉伯数字、英文字母、普通符号的标准ASCII码(128个),以及扩展部分欧洲语言字符之后的ASCII扩展码(256个),仍然无法完全表示比如中文、日文等其他语言字符。

  所以各个国家便着手本国语言的编码,例如:中国国家标准总局1980年发行的GB2312以及之后的扩展版本GBK和GB18030。这导致了世界上存在着多种编码方式,出现了同一个二进制数字可以被解释成不同字符的现象。

  GB2312因为只表示普通数字、字母、汉字,不表示其他语言,所以使用两个字节已经足够,但是它和汉字的映射,与之后的Unicode和汉字的映射没有任何关系。

  比如汉字“”在Unicode中对应的字符集是“4E 00”,而在GB2312中对应的字符集是“D2 BB”。



五、Unicode(统一码、万国码)

  要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。

  所以,就需要一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。

  直到之后出现了一个全球统一的编码规则叫Unicode,Unicode就像它的名字所表示的,这是一种包含所有符号的编码,它是为整合全世界的所有语言文字而诞生的。

  任何文字在Unicode中都对应一个唯一的值,这个值称为代码点(code point)。

1. Unicode字符集

  Unicode编码点分为17个平面(plane),每个平面包含2的16次(即65536)个码位(code point)。

  17个平面的码位可表示为从U+xx0000到U+xxFFFF。

  其中xx表示十六进制值从00到10(16进制),共计17个平面。

    第一个00平面称为“基本多语言平面”(Basic Multilingual Plane,简称BMP)。
    剩下16个平面(01-10)称为“辅助平面”(Supplementary Planes)。
    Unicode标准规定其编码使用范围并不超过0x10FFFF

  Unicode字符集中汉字的范围是4E00 ~ 9FA5。4E00是汉字“一”。

  补充:鉴于 Unicode 原有的16位元空间不足以应用,从 Unicode 3.1 版本开始,设立了16个辅助平面,使 Unicode 的可使用空间由六万多字增至约一百万字。原有的 Unicode 空间称为基本平面或基本多文种平面 (Basic Multilingual Plane, 简称 BMP)。辅助平面字符要用上4字节来储存。

2. Unicode存在的两个问题

(1)如何才能区分Unicode和ASCII?
  计算机对数据的读取是按照一个字节的大小来读取识别的,计算机怎么知道三个字节表示的是一个字符,而不是分别表示三个字符呢?

(2)一个字符用统一的字节数来表示,会造成存储空间的浪费。
  我们已经知道,英文字母只用一个字节的ASCII码表示就够了,如果Unicode统一规定每个字符需要用相同的字节数来表示,每个字符用两个、三个,甚至四个字节表示,那么每个英文字母前都必然有一到三个字节全是二进制数0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

  注意:Unicode只是一个符号集,它只规定了各个字符所对应的二进制数,并没有规定在计算机中如何存储以及传输的问题。

5种编码方式
对比UTF-8UTF-16UTF-32UCS-2UCS-4
编码空间0 ~ 10FFFF0 ~ 10FFFF0 ~ 10FFFF0 ~ FFFF0 ~ 7FFFFFFF
最少编码字节数12424
最多编码字节数44424
是否依赖字节序

  UTF-16可看成是UCS-2的父集,UTF-32可看成是UCS-4的子集。



六、UCS(Unicode的定长字符编码

  通用多八位编码字符集(Universal Multiple-Octet Coded Character Set)也叫通用字符集(Universal Character Set, UCS),是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。

  通用多八位编码字符集包括了其他所有字符集。它保证了与其他字符集的双向兼容,即,如果你将任何文本字符串翻译到UCS格式,然后再翻译回原编码,你不会丢失任何信息。

1. UCS-2

  UCS-2(Universal Character Set coded in 2 octets),是用定长2个字节来表示字符(定长编码),其取值范围为 U+0000~U+FFFF。

  Unicode当前默认的版本是UCS-2,UCS-2 编码 与 Unicode码 完全一样,6w+的字符量已经足以用于全球的主要语言的大多数字符。

2. UCS-4

  但是Unicode为了能表示更多的文字,还是提供了一个扩展机制(UCS-4,用四个字节表示代码点,最高位为0,取值范围为 U+00000000~U+7FFFFFFF),允许表示一百多万个字符。


  比如,英文字母“A”对应的Unicode(十六进制)是U+0041,转换为十进制是65,转换为二进制是0100 0001,和ASCII码一致,只需要一个字节表示。

  比如,中文“”对应的Unicode(十六进制)是U+4E00,转换为十进制是19968,转换为二进制是100 1110 0000 0000,这个二进制有15位,需要至少2个字节表示。

  具体的符号对应表,可以查询Unicode官网,也可以查询专门的汉字对应表,还有字符与Unicode编码在线转换



七、UTF(Unicode的变长字符编码)

  随着互联网的普及,为了解决如何来表示Unicode、如何让计算机读懂Unicode的问题,强烈需要一种统一规定存储格式的编码方式,即UTF(Unicode Transformation Format),是Unicode的变长字符编码的方式。

  Unicode的实现方式包括UTF-8、UTF-16、UTF-32,其中 UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。

编码类型字节长度说明
UTF-81~4由1~4个字节变长
UTF-162~42或4个字节变长,大部分是2字节,对于ASCII空间浪费
UTF-3244个字节表示,空间极大浪费

1. UTF-8(Unicode的一种可变长度字符编码实现方式)


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

  UTF-8 的规则很简单,只有两条:

  (1)对于单字节的符号,字节的最高位二进制数设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和最初的前128个ASCII标准码是完全相同的。

第一位第二位第三位第四位第五位第六位第七位第八位
最高位必须为0字符的Unicode码

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

- 第一个字节:
    - 高位前n位为`1`
    - 第n+1位为`0`
- 其他字节:
    - 高位以`10`开头
- 未提及的位使用对应的unicode补充,不足的在高位用0补充
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Unicode 和 UTF-8 的映射关系如下表:
(UTF-8 编码方式中的x为字符的Unicode二进制编码)

Unicode符号范围
(十六进制)
UTF-8 编码方式
(二进制)
说明
00 00 00 00 ~ 00 00 00 7F0xxxxxxx完全兼容ASCII
00 00 00 80 ~ 00 00 07 FF110xxxxx 10xxxxxx110表示需要用两个字节(当前字节和随后一个字节)来表示当前字符
00 00 08 00 ~ 00 00 FF FF1110xxxx 10xxxxxx 10xxxxxx1110表示需要用三个字节来表示当前字符
00 01 00 00 ~ 00 10 FF FF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx同上,11110表示需要四个字节

  总结,UTF-8 就是使用控制码+字符码组成,控制码就是告诉计算机当前是单字节还是多字节,字符码就是对应的Unicode。

  比如,汉字“”对应的Unicode(十六进制)是4E 004E 0008 00 ~ FF FF的范围内,所以对应的 UTF-8 需要三个字节。4E 00对应的二进制为100 1110 0000 0000,加上控制码后,对应的 UTF-8 为11100100 10111000 10000000,控制码后面的高位不足时,用0补充。

2. UTF-8 和 UTF-8 BOM

  BOM(Byte Order Mark),字节顺序标记,出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码,是UTF编码方案里用于标识编码的标准标记。

  BOM是为 UTF-16 和 UTF-32 准备的,用户标记字节序(Byte Order)。拿UTF-16来举例,其是以两个字节为编码单元,在解释一个 UTF-16 文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是59 4E,“乙”的Unicode编码是4E 59。如果我们收到 UTF-16 字节流“59 4E”,那么这是“奎”还是“乙”?(详情请看下一节Little endian 和 Big endian部分)

  UTF-8是以字节为编码单元,没有字节序的问题。

  UTF-8 文件中放置BOM主要是微软的习惯,但是放在别的系统上会出现问题。

  不含BOM的UTF-8才是标准形式。

  UTF-8 BOM是微软在自己的 UTF-8 格式的文本文件之前加上了“EF BB BF”三个字节,Windows上的“Notepad(记事本)”等程序就是根据这三个字节来确定一个文本文件是 ASCII 的还是 UTF-8 的,然而这个只是微软暗自作的标记,其它平台上并没有对 UTF-8 文本文件做个这样的标记。

3. Little endian 和 Big endian

  上一节已经提到,UCS-2 格式可以存储 Unicode 码(码点不超过0xFFFF)。以汉字“”为例,Unicode 码是54 68,需要用两个字节存储,一个字节是54,另一个字节是68。存储的时候,54在前,68在后,这就是Big endian方式;68在前,54在后,这是Little endian方式。

  这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

 - 第一个字节在前,就是“大头方式”(Big endian)。

 - 第二个字节在前,就是“小头方式”(Little endian)。
  • 1
  • 2
  • 3

  那么,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

  Unicode规范中推荐的标记字节顺序的方法是BOM。在UCS编码中,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE),用FE FF表示。这正好是两个字节,而且FFFE1

  注意:FE FF在UCS中是不可见的字符,所以不应该出现在实际字节流传输中。

  UCS规范建议我们在传输字节流前,先传输“ZERO WIDTH NO-BREAK SPACE”字符。

 - 如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式。

 - 如果一个文本文件的头两个字节是FF FE,就表示该文件采用小头方式。
  • 1
  • 2
  • 3


八、记事本notepad.exe中的几种编码方式

  微软Windows平台,有一个最简单的Unicode和 UTF-8 转化方法,就是使用内置的记事本程序notepad.exe。打开文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条。
notepad.exe
  “编码”里面有四个选项:ANSIUTF-16 LEUTF-16 BEUTF-8UTF-8 BOM
  (1)ANSI编码是不是一种特定的编码方式,具体是要取决于操作系统。
    对于英文文件是ASCII编码,对于日文文件是JIS编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。
  (2)UTF-16 LE编码指的是UTF-16编码方式,采用Little endian格式(原来顺序)。
  (3)UTF-16 BE编码指的是UTF-16编码方式,采用Big endian格式(颠倒顺序)。
  (4)UTF-8编码指的是不带BOM的 UTF-8 编码。
  (5)UTF-8 BOM编码指的是带BOM的 UTF-8 编码。
  从Windows10开始,记事本notepad.exe已经将带BOM和不带BOM的分开来了。



参考文献:
[1] Unicode官网
[2] 专门的汉字对应表
[3] 阮一峰的《字符编码笔记》
[4] 熊猫儿的《一文看懂ASCII,UNICODE,UTF8编码规则》
[5] ivy_0709的《详解windows记事本的4种编码方式》
[6] 我(零号萌新)的《ASCII美国信息交换标准代码表》
[7] 工具:字符与Unicode编码在线转换

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/924918
推荐阅读
相关标签
  

闽ICP备14008679号