突然间想搞清楚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里对应关系。
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 - Unicode字符编码五层次模型
试着用自己的语句把自己的理解表达出来,但还是有点乱哈