[资料]字符编码详解,系数ASCII、ANSI、Unicode、UTF-8、UTF-16

  • ~8.04K 字
  • 次阅读
  1. 1. 基本知识
  2. 2. ASCII-SBCS
    1. 2.1. ASCII码表
      1. 2.1.1. ASCII控制字符
      2. 2.1.2. ASCII可显示字符
  3. 3. ANSI-DBCS
  4. 4. Unicode - UCS - 万国码
    1. 4.1. UTF - Unicode/UCS Transformation Format
  5. 5. UCS-2、UCS-4与UTF-16、UTF-32
    1. 5.1. 字节顺序标记-BOM
  6. 6. 扩展阅读

突然间想搞清楚unicode以及utf-8之间的关系,虽说之前有点印象,但还是云里雾里的,于是查了下。简单说就是太混乱,没弄清楚也跑出来写文章的很多,很难有文章能真正全说清楚的。当然我也是按我的理解来写的,不一定都对。

基本知识

字符集 - Character Set
编码 - encoding
代码页 - CodePage
代码页是一个选定字符代码的列表,与字符集其实是差不多的概念,只不过代码页是计算机用来切换编码的概念(从Page来理解)。最早来自IBM,后来被微软,oracle ,SAP等广泛采用。由于最开始每个国家都在搞自己的locale编码(也就是ANSI,随后会有详细解释),导致每个国家都不统一,不兼容,可能导致冲突,所以一个系统在处理文字的时候,必须要告诉计算机你的编码是哪个国家和地区的标准,这种国家和标准的代号(其实就是字符编码格式的代号),微软称为Codepage(代码页),其实这个代码页和字符集编码的意思是一样的。告诉你代码页,本质就是告诉了你编码格式。
但是不同厂家的代码页可能完全不同(这个全看厂家怎么放,没有标准,当然一个公司一般也不会随便改自己的代码页),比如, UTF-8字符编码 在IBM对应的代码页是1208,在微软对应的是65001,在德国的SAP公司对应的是 4110
GBK的在微软的代码页是936,告诉你代码页是936其实和告诉你我编码格式是GBK效果完全相同。那么处理文本的时候就不会有问题,不会去考虑某个代码是显示的韩文还是中文,同样,日文和韩文的代码页就和中文不同,这样就可以避免编码冲突导致计算机不知如何处理的问题。当然用这个也可以很容易的切换语言版本。
内码
指操作系统内部的字符编码,中国人的原创词,可以理解为没有任何组织定义过这个词。
区位码
汉字GB2312编码里的概念,不需要特别理解

ASCII-SBCS

ASCII又称SBCS(单字节字符集)
ASCII(American Standard Code for Information Interchange)美国信息交换标准代码,这是计算机上最早使用的通用的编码方案。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。

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

ASCII 这部标准本身就直接规定了字符和字符编码的方式,所以既是字符集又是编码方案。
无论是ANSI标准编码还是Unicode都包含ASCII,通常的乱码都是由非ASCII字符造成的

ASCII码表

ASCII控制字符

二进制 十进制 十六进制 缩写 可以显示的表示法 名称/意义
0000 0000 0 00 NUL ␀ 空字符(Null)
0000 0001 1 01 SOH ␁ 标题开始
0000 0010 2 02 STX ␂ 本文开始
0000 0011 3 03 ETX ␃ 本文结束
0000 0100 4 04 EOT ␄ 传输结束
0000 0101 5 05 ENQ ␅ 请求
0000 0110 6 06 ACK ␆ 确认回应
0000 0111 7 07 BEL ␇ 响铃
0000 1000 8 08 BS ␈ 退格
0000 1001 9 09 HT ␉ 水平定位符号
0000 1010 10 0A LF ␊ 换行键
0000 1011 11 0B VT ␋ 垂直定位符号
0000 1100 12 0C FF ␌ 换页键
0000 1101 13 0D CR ␍ 归位键
0000 1110 14 0E SO ␎ 取消变换(Shift out)
0000 1111 15 0F SI ␏ 启用变换(Shift in)
0001 0000 16 10 DLE ␐ 跳出数据通讯
0001 0001 17 11 DC1 ␑ 设备控制一(XON 启用软件速度控制)
0001 0010 18 12 DC2 ␒ 设备控制二
0001 0011 19 13 DC3 ␓ 设备控制三(XOFF 停用软件速度控制)
0001 0100 20 14 DC4 ␔ 设备控制四
0001 0101 21 15 NAK ␕ 确认失败回应
0001 0110 22 16 SYN ␖ 同步用暂停
0001 0111 23 17 ETB ␗ 区块传输结束
0001 1000 24 18 CAN ␘ 取消
0001 1001 25 19 EM ␙ 连接介质中断
0001 1010 26 1A SUB ␚ 替换
0001 1011 27 1B ESC ␛ 跳出
0001 1100 28 1C FS ␜ 文件分割符
0001 1101 29 1D GS ␝ 组群分隔符
0001 1110 30 1E RS ␞ 记录分隔符
0001 1111 31 1F US ␟ 单元分隔符
0111 1111 127 7F DEL ␡ 删除

ASCII可显示字符

二进制 十进制 十六进制 图形
0010 0000 32 20 (空格)(␠)
0010 0001 33 21 !
0010 0010 34 22 "
0010 0011 35 23 #
0010 0100 36 24 $
0010 0101 37 25 %
0010 0110 38 26 &
0010 0111 39 27 '
0010 1000 40 28 (
0010 1001 41 29 )
0010 1010 42 2A *
0010 1011 43 2B +
0010 1100 44 2C ,
0010 1101 45 2D -
0010 1110 46 2E .
0010 1111 47 2F /
0011 0000 48 30 0
0011 0001 49 31 1
0011 0010 50 32 2
0011 0011 51 33 3
0011 0100 52 34 4
0011 0101 53 35 5
0011 0110 54 36 6
0011 0111 55 37 7
0011 1000 56 38 8
0011 1001 57 39 9
0011 1010 58 3A :
0011 1011 59 3B ;
0011 1100 60 3C <
0011 1101 61 3D =
0011 1110 62 3E >
0011 1111 63 3F ?
0100 0000 64 40 @
0100 0001 65 41 A
0100 0010 66 42 B
0100 0011 67 43 C
0100 0100 68 44 D
0100 0101 69 45 E
0100 0110 70 46 F
0100 0111 71 47 G
0100 1000 72 48 H
0100 1001 73 49 I
0100 1010 74 4A J
0100 1011 75 4B K
0100 1100 76 4C L
0100 1101 77 4D M
0100 1110 78 4E N
0100 1111 79 4F O
0101 0000 80 50 P
0101 0001 81 51 Q
0101 0010 82 52 R
0101 0011 83 53 S
0101 0100 84 54 T
0101 0101 85 55 U
0101 0110 86 56 V
0101 0111 87 57 W
0101 1000 88 58 X
0101 1001 89 59 Y
0101 1010 90 5A Z
0101 1011 91 5B [
0101 1100 92 5C \
0101 1101 93 5D ]
0101 1110 94 5E ^
0101 1111 95 5F _
0110 0000 96 60 `
0110 0001 97 61 a
0110 0010 98 62 b
0110 0011 99 63 c
0110 0100 100 64 d
0110 0101 101 65 e
0110 0110 102 66 f
0110 0111 103 67 g
0110 1000 104 68 h
0110 1001 105 69 i
0110 1010 106 6A j
0110 1011 107 6B k
0110 1100 108 6C l
0110 1101 109 6D m
0110 1110 110 6E n
0110 1111 111 6F o
0111 0000 112 70 p
0111 0001 113 71 q
0111 0010 114 72 r
0111 0011 115 73 s
0111 0100 116 74 t
0111 0101 117 75 u
0111 0110 118 76 v
0111 0111 119 77 w
0111 1000 120 78 x
0111 1001 121 79 y
0111 1010 122 7A z
0111 1011 123 7B {
0111 1100 124 7C
0111 1101 125 7D }
0111 1110 126 7E ~

ANSI-DBCS

ANSI,American National Standards Institute
个人感觉理论上来讲其实ANSI不算是一种编码,从缩写可以看出,这是一个标准制定协会。应该是它把各地的locale编码都给记录为相应的标准(遗憾的是搜索不到相应的文章,网上都会非常欣喜的告诉你,有好多种ANSI编码。)wiki上有句话"ANSI is a bit of a misnomer as the behavior does not exactly match the ANSI standards and other codepages can be selected, most recently UTF-8 Unicode."来源于https://en.wikipedia.org/wiki/Windows_code_page,可惜我英文不是很好。从微软的Code Page Identifiers可以看到如下

  • ANSI/OEM Thai (ISO 8859-11); Thai (Windows)
  • ANSI/OEM Japanese; Japanese (Shift-JIS)
  • ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
  • ANSI/OEM Korean (Unified Hangul Code)
  • ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)

Windows 里说的「ANSI」其实是根据当前 locale 选定具体的编码,比如简中 locale 下是 GBK。把自己这些 code page 称作「ANSI」是 Windows 的臭毛病。通常来讲,GB、BIG5、 Shift-JIS都属于ANSI编码。
DBCS(Double-byte Character Sets)的意思是双字节字符集
also known as an "expanded 8-bit character set", is an extended single-byte character set (SBCS), implemented as a code page. (DBCS是SBCS的扩展)
在这一方案下,字符的宽度可以是一个字节,也可是两个字节。如果字符的宽度是两个字节,那么它的第一个字节就是一个特殊的“前导字节”,该字节是根据所使用的代码页从某个特定范围选定的。前导字节和“尾字节”合起来指定一个唯一的字符编码。
各个ANSI码(GB、BIG5、 Shift-JIS)是由于早期各个国家搞自己的字符编码造成的,这些国家的编码区间都是重叠的。举个例子,一个ANSI的文本文档从中文环境放到日文环境下就会乱码。

Unicode - UCS - 万国码

通用字符集 - UCS(Universal Character Set)
首先要说明的是Unicode和UCS并不是完全相同的概念

Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。Unicode符号需要字节数不等,从1个字节到4个字节,甚至更多。这里就有个严重的问题,计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果Unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。出于节省空间的目的,对Unicode编码的实现方式有所不同。

Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)
把带有 BOM 的小端序 UTF-16 称作「Unicode」也是 Windows 的臭毛病。
简单说Windows记事本里的Unicode会误导别人。Unicode本身是没有大端序以及小端序的区别的。

UTF - Unicode/UCS Transformation Format

UTF-8编码字节含义

  • UTF-8编码中的任意字节B,如果B的第一位为0,则B为ASCII码且B独立的表示一个字符;
  • 如果B的第一位为1,第二位为0,则B为一个多字节字符中的后续字节;
  • 如果B的前两位为1,第三位为0,则B为两个字节的字符中的第一个字节;
  • 如果B的前三位为1,第四位为0,则B为三个字节的字符中的第一个字节;
  • 如果B的前四位为1,第五位为0,则B为四个字节的字符中的第一个字节;

因此,对UTF-8编码中的任意字节,根据第一位,可判断是否为ASCII字符;根据前二位,可判断该字节是否为一个字符编码的第一个字节;根据前四位(如果前两位均为1),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;根据前五位(如果前四位为1),可判断编码是否有错误或数据传输过程中是否有错误。
在ASCII字符较多的情况下,UTF-8比UTF-16更节省空间,而在中文字符较多的情况下(UTF-8一个中文字符3字节,UTF-16仍然是两个)UTF-16占用空间更少,UTF-16、UTF-32不是UTF-8的升级。

字符 UTF-8 UTF-16(LE)
! 21(00100001) 00 21(00000000 00100001)
☺ E2(11100010) 98(1001100) BA(10111010) 26 3A(0010,0110 00,111010)
我 E6(11100110) 88(10001000) 91(10010001) 62 11(0110,0010 00,010001)

注:LE为小端序,上表中UTF-16(LE)里的","用于标出和UTF-8里对应关系。

可以在这里UTF-8以及这里UTF-16 LE验证

UCS-2、UCS-4与UTF-16、UTF-32

UCS-2对每一个Unicode码位使用2bytes字集(16位bit);
UCS-4对每一个Unicode码位使用4bytes字集(32位bit);
UTF-16可看成是UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为UTF-16了。现在若有软件声称自己支持UCS-2编码,那其实是暗指它不能支持在UTF-16中超过2bytes的字集。对于小于0x10000的UCS码,UTF-16编码就等于UCS码。
UTF-32 原本是 UCS-4 的子集,但JTC1/SC2/WG2声明,所有未来对字符的指定都将会限制在BMP及其14个补充平面。
于是就现状而言,除了 UTF-32 标准包含额外的 Unicode 意涵,UCS-4 和 UTF-32 大体是相同的。

字节顺序标记-BOM

编码 表示(十六进制) 表示(十进制)
UTF-8 EF BB BF 239 187 191
UTF-16(大端序) FE FF 254 255
UTF-16(小端序) FF FE 255 254
UTF-32(大端序) 00 00 FE FF 0 0 254 255
UTF-32(小端序) FF FE 00 00 255 254 0 0
UTF-7 2B 2F 76和以下的一个字节:[ 38 、 39、 2B、2F ] 43 47 118和以下的一个字节:[ 56、57 、43、47 ]
en:UTF-1 F7 64 4C 247 100 76
en:UTF-EBCDIC DD 73 66 73 221 115 102 115
en:Standard Compression Scheme for Unicode 0E FE FF 14 254 255
en:BOCU-1 FB EE 28 及可能跟随着FF 251 238 40 及可能跟随着255
GB-18030 84 31 95 33 132 49 149 51
由于UTF-8没有大端序以及小端序的区别,在Linux等系统中,是不带BOM头的,而微软在记事本的保存中都会默认带上BOM头用于区别ANSI文本文档。

扩展阅读

  • MBCS(multibyte character set):在微软中,一般都是指DBCS,而Wiki认为微软用词不当

https://en.wikipedia.org/wiki/Variable-width_encoding#CJK_multibyte_encodings


试着用自己的语句把自己的理解表达出来,但还是有点乱哈

打赏
打赏提示信息
分享
分享提示信息