字符编码
字符编码,近年来一直困扰着我,感觉平常遇到的UTF-8,GBK,Unicode,ANSI等编码大致知道意思也就可以了,没有必要去给它一个细分。
但是,今天发现不得不去好好梳理一下他们的关系了。因为这个地方老是出些莫名其妙的问题。
1. 字符集和字符编码
首先明确两个概念,“字符集”(charset)和“字符编码”(encoding)。有些地方经常把这两个概念等同,比如说到ASCII码,有时候指“字符集”,有时候指“字符编码”,其实这是两个不同的概念,混淆了这两个概念,很难真正理解一些概念,比如Unicode和Utf8、Utf16的关系(其实Unicode是字符集和第一层字符编码,Utf8、Utf16是第二层字符编码,它们都表示了同一个字符集)。
字符集顾名思义是“许多字符的集合”,这些字符组成一套符号系统,可以组合起来形象的表达各种含义。比如26个英文字母加上标点符号可以组成“英文字符集”,这个字符集的组合可以形成英美人可以理解的一套文字系统,看到了“I love you”,就能明白什么意思。再比如新华字典中的所有汉字加上标点符号可以组成“中文字符集”,这个字符集的组合可以形成中文文字系统,看到“我爱你”就能理解其含义。对于老外,如果不懂中文,看到“我爱你”三个字符,可能以为就是“鬼画符”。
“字符编码”字面意思就是“对字符进行编码”。呵呵,听起来有点废话。那先说下为什么要对字符进行编码。对字符编码的最大目的还是为了传输、储存信息(其实储存也是为了传输,是为了能传给以后的人看)。
字符编码的四个步骤
从上一节来看,“字符集”是一种形象表意的工具,“字符编码”是表示字符的一种方式。在计算机出现之前就已经有了这两种技术。计算机中,是使用二进制的方式对字符集重新编码。
在计算机中,要建立一种“字符编码模型”,需要四步:
- 要有一个字符库,确定这些字符足够表意。 比如ASCII字符集,已经足够表示英语,但不能表示中文,于是产生GB2312字符集。
- 第一层编码,给每个字符编个数字,英文叫Code Point 或 Code Position。比如ASCII字符集中,65表示“A”,97表示“a”。
- 第二层编码,确定表示字符的二进制位数(8位,16位,32位)。ASCII使用7位,DBCS(双字节字符集)使用16位。
- 第三层编码,确定字符二进制值的存储格式(大端法,小端法)。比如X86机器使用小端法。
一种字符集一般只有一种编码方式,当字符集不够用时,会增加一些新的符号,形成新的字符集。对于新的符号会有新的数字,新的编码格式。所以有时“字符集”和“字符编码”的概念并不严格区分。比如ASCII码,可以指128个字符的字符集,也可以指对这128个字符的编码方式。不过有的字符集有多种编码格式,比如Unicode字符集,Utf8、Utf16都是其编码格式(第二层编码)。
2 常用计算机编码
2.1 ASCII码
全称“American Standard Code for Information Interchange”,美国标准信息交换码,由美国标准委员会(American Standards Association,简称ASA)制定,后来该协会改组为“美国国家标准学会”(American National Standard Institute , 简称ANSI ),所以很多资料上说ASCII码是ANSI制定的。ASCII码是从电报码发展过来的,最早使用是用在7-bit的电传打字机上的。1960年10月6日,ASA开始ASCII的标准化工作,于1963年发布第一版,1967年再发布一次大的版本,这个标准版本,也是一个7-bit码,包含33个非打印字符(现在许多已经废弃了),95个打印字符(包含空格符),编码范围为0~127。
注意,这个最初是美国的标准,包含的95个打印字符中,无法囊括世界上所有国家的字符,比如英镑符号“£”,各种拉丁符号“δ、β、θ”,中文、日文、韩文这么多象形文字等等。为了解决这个问题,各国都制定了自己的字符集和字符编码,不过,*本上都兼容7-bti ASCII码。比如ISO-8859系列,日文的JIS,中国大陆的GB2312、GBK,台湾的Big5等。
2.2 Extended ASCII码
最初的标准ASCII码中包含的字符太少,很多应用或者国家中的符号都无法表示。比如数学符号“× ÷ ≠ ≥ ≈ π”。尤其20世纪70年代,随着PC的兴起,各电脑厂商开始增加自己的图形符号,形成了各种非标准的扩展ASCII码字符集(比如,ATASCII,PETSCII等)。TRS-80(美国早期的一种家庭电脑),增加了32个图形字符。
当时的IBM也为自己的PC定制了8-bit扩展ASCII码字符集,叫做代码页(code page),给不同语言制定不同的 code page,并把这些 code page 编号。这些 code page 都是兼容标准ASCII的。编码的数值为,从128-255扩展编码。比如,北美市场的DOS电脑,使用 code page 437,包含了法语、德语和一些其他欧洲国家的带音调的字符。code page 技术一直保留了下来,发展到现在,微软的windows内部就用了这种技术。
苹果电脑也在 Mac OS 系统中引入了自己的8-bit扩展ASCII编码,如 Mac OS Roman。国家的带音调的字符。DEC公司也开发了 MCS(Multinational Character Set,多国字符集)。
其实标准的ASCII就是7-bit的编码(8字节,但是最高位没有编码),后来使用过程中发现127个字符有点不够用,于是将ASCII进行了扩展,叫做Extended-ASCII或者high-ASCII,8位的,能表示256个字符。由于不同的应用场景,有不同的编码,有IBM的Extend ASCII和ANSI的Extend ASCII。去wikipedia上会发现有好多种ASCII的标准,大类就是IBM和ANSI(Windows的,微软很强势,ANSI的东西感觉就是给他们家用的)两种,其实都是为了给自家系统用的,随着IBM操作系统的坠落,IBM的扩展ASCII也*本上淡出视野。
wikipedia,Revisions of the ASCII standard:
ASA X3.4-1963[1][4][16][17]
ASA X3.4-1965 (approved, but not published, nevertheless used by IBM 2260 & 2265 Display Stations and IBM 2848 Display Control)[1]:423, 425–428, 435–439[16][17]
USAS X3.4-1967[1][5][17]
USAS X3.4-1968[1][17]
ANSI X3.4-1977[17]
ANSI X3.4-1986[7][17]
ANSI X3.4-1986 (R1992)
ANSI X3.4-1986 (R1997)
ANSI INCITS 4-1986 (R2002)[18]
ANSI INCITS 4-1986 (R2007)[19]
ANSI INCITS 4-1986 (R2012)
看到没,早期有四个版本是IBM的。
扩展的ASCII的产生
既然IBM的扩展ASCII已经成为昨日黄花,我们只考虑ANSI的扩展ASCII的出现契机。
搭载Windows系统的计算机进入欧洲之后,发现标准的ASCII并不能满足欧洲这些拉丁语族国家的语言表意,决定对其进行扩展。同为印欧语系,发现扩展起来也没那么难,总共256个值就包括所有了。只需要将原来的7-bit扩展为8-bit,将原来的标准ASCII保留,第一位使用0来表示。将扩展的字符第一位使用1来表示
扩展ASCII的组成
具体来讲,扩展后的ASCII码表可以看成由三部分组成:
第一部分:由00H到1FH共32个,一般用来通讯或作为控制之用。有些可以显示在屏幕上,有些则不能显示,但能看到其效果(如换行、退格)
第二部分:是由20H到7FH共96个,这95个字符是用来表示阿拉伯数字、英文字母大小写和下划线、括号等符号,都可以显示在屏幕上.
第三部分:由80H到0FFH共128个字符,一般称为"扩充字符",这128个扩充字符是由IBM制定的,并非标准的ASCII码.这些字符是用来表示框线、音标和其它欧洲非英语系的字母。
ascii值 字符 unicode
128 Ç 0xc7
129 ü 0xfc
130 é 0xe9
131 â 0xe2
132 ä 0xe4
133 à 0xe0
134 å 0xe5
135 ç 0xe7
136 ê 0xea
137 ë 0xeb
138 è 0xe8
139 ï 0xef
140 î 0xee
141 ì 0xec
142 Ä 0xc4
143 Å 0xc5
144 É 0xc9
145 æ 0xe6
146 Æ 0xc6
147 ô 0xf4
148 ö 0xf6
149 ò 0xf2
150 û 0xfb
151 ù 0xf9
152 ÿ 0xff
153 Ö 0xd6
154 Ü 0xdc
155 ¢ 0xa2
156 £ 0xa3
157 ¥ 0xa5
158 ₧ 0x20a7
159 ƒ 0x192
160 á 0xe1
161 í 0xed
162 ó 0xf3
163 ú 0xfa
164 ñ 0xf1
165 Ñ 0xd1
166 ª 0xaa
167 º 0xba
168 ¿ 0xbf
169 ⌐ 0x2310
170 ¬ 0xac
171 ½ 0xbd
172 ¼ 0xbc
173 ¡ 0xa1
174 « 0xab
175 » 0xbb
176 ░ 0x2591
177 ▒ 0x2592
178 ▓ 0x2593
179 │ 0x2502
180 ┤ 0x2524
181 ╡ 0x2561
182 ╢ 0x2562
183 ╖ 0x2556
184 ╕ 0x2555
185 ╣ 0x2563
186 ║ 0x2551
187 ╗ 0x2557
188 ╝ 0x255d
189 ╜ 0x255c
190 ╛ 0x255b
191 ┐ 0x2510
192 └ 0x2514
193 ┴ 0x2534
194 ┬ 0x252c
195 ├ 0x251c
196 ─ 0x2500
197 ┼ 0x253c
198 ╞ 0x255e
199 ╟ 0x255f
200 ╚ 0x255a
201 ╔ 0x2554
202 ╩ 0x2569
203 ╦ 0x2566
204 ╠ 0x2560
205 ═ 0x2550
206 ╬ 0x256c
207 ╧ 0x2567
208 ╨ 0x2568
209 ╤ 0x2564
210 ╥ 0x2565
211 ╙ 0x2559
212 ╘ 0x2558
213 ╒ 0x2552
214 ╓ 0x2553
215 ╫ 0x256b
216 ╪ 0x256a
217 ┘ 0x2518
218 ┌ 0x250c
219 █ 0x2588
220 ▄ 0x2584
221 ▌ 0x258c
222 ▐ 0x2590
223 ▀ 0x2580
224 α 0x3b1
225 ß 0xdf
226 Γ 0x393
227 π 0x3c0
228 Σ 0x3a3
229 σ 0x3c3
230 µ 0xb5
231 τ 0x3c4
232 Φ 0x3a6
233 Θ 0x398
234 Ω 0x3a9
235 δ 0x3b4
236 ∞ 0x221e
237 φ 0x3c6
238 ε 0x3b5
239 ∩ 0x2229
240 ≡ 0x2261
241 ± 0xb1
242 ≥ 0x2265
243 ≤ 0x2264
244 ⌠ 0x2320
245 ⌡ 0x2321
246 ÷ 0xf7
247 ≈ 0x2248
248 ° 0xb0
249 ∙ 0x2219
250 · 0xb7
251 √ 0x221a
252 ⁿ 0x207f
253 ² 0xb2
254 ■ 0x25a0
255 ÿ 0xff
2.3 ISO-8859
由于各公司、国家之间都有自己的字符集,同一个数值,在不同的字符集之间表示的符号可能不一样,这样在一台电脑上正常可以阅读的文件,到另外一台电脑可能就成了乱码。为了解决这个问题,ISO组织统一了一套标准字符集,就是ISO-8859.
不过 ISO-8859 不是一个字符集,而是一系列扩充的ASCII码字符集。
ISO/IEC 8859-1 (Latin-1) - 西欧语言
ISO/IEC 8859-2 (Latin-2) - 中欧语言
ISO/IEC 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
ISO/IEC 8859-4 (Latin-4) - 北欧语言
ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
ISO/IEC 8859-6 (Arabic) - 阿拉伯语
ISO/IEC 8859-7 (Greek) - 希腊语
ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
ISO 8859-8-I - 希伯来语(逻辑顺序)
ISO/IEC 8859-9(Latin-5 或 Turkish)- 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
ISO/IEC 8859-10(Latin-6 或 Nordic)- 北日耳曼语支,用来代替Latin-4。
ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
ISO/IEC 8859-13(Latin-7 或 Baltic Rim)- 波罗的语族
ISO/IEC 8859-14(Latin-8 或 Celtic)- 凯尔特语族
ISO/IEC 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元(€)符号。
ISO/IEC 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
由于英语没有任何重音字母(不计外来词),故可使用以上十五个字集中的任何一个来表示。至于德语方面,因它除了 A-Z, a-z 外,只用 Ä, Ö, ü, ä, ö, ß, ü 七个字母,而所有拉丁字集(1-4, 9-10, 13-16)均有此七个字母,故德语可使用以上十个字集中的任何一个来表示。
此系列中没有-12号的原因是,此计划原本要设计成一个包含塞尔特语族字符集的“Latin-7”,但后来塞尔特语族变成了ISO 8859-14 / Latin-8。亦有一说谓-12号本来是预留给印度天城体梵文的,但后来却搁置了。
IOS-8859-1 这个编码向下兼容ASCII,但是已经不是标准的ASCII了,因为不能互相转换(只能单向转换),它有新的名字。这个编码是在Windows(绑架ANSI)进入欧洲(ISO组织可能老巢在欧洲)时候一起搞出来的,标准编号叫做ANSI/ISO-8859-1-1987,简称ISO-8859-1。编码全称叫做「American National Standard for Information Processing-8-Bit Single-Byte Coded Graphic Character Sets-Part 1: Latin Alphabet No 1」,所以也简写作Latin-1,mysql设置的时候就会设置成latin1
因为拉丁语系的国家太多,欧洲这片大陆也是动乱不安,ISO-8859-1一个是不够的,根据不同的地方,搞出了很多ISO-8859系的标准,具体可以见百度百科,从1到16。。。
我们常用的是IOS-8859-1,叫做“西欧字符集”。
由于这个字符集包括了印欧语系,也就是当今世界大部分技术、开发工具发源地。。很多语言标准、开发工具的编码格式默认是IOS-8859-1,这也是中文乱码的一个坑。
2.4 MBCS、DBCS
上面所说的ASCII码、扩展ASCII码、ISO-8859中每个字符都是一个字节(8-bit)可以表示的,所以称为“单字节字符集”(Single-Byte Character Set,简称SBCS)。
单字节字符集最多只能同时表示256个字符,ISO-8859中总字符数可能超过256个,但同时能使用的字符要么是8859-1字符集中的,要么是8859-2字符集中的,每个字符集最多仍然是256个,如果一篇文章中要出现所有语系中的字符,也是做不到的。
但是到了亚洲,中、日、韩等国家文字,每个文字都是一个符号,远远超过256个字符。于是,亚洲国家制定了自己的字符集,使用1个或2个或以上的字节数表示自己的字符集,这就是“多字节字符集”(Multi-Bytes Character Sets,简称MBCS)。
windows 系统中,本地字符集就是MBCS,不过由于大部分字符是2字节的,所以又称为“双字节字符集”(Double-Bytes Character Sets,简称DBCS),所以有的时候看到MBCS、DBCS,都是一回事。MBCS是完全兼容标准ASCII码的。
2.5 GB2312、GB13000、GBK、GB18030
这几种字符都是中国国家标准委员会制定的,简称“GB”(国标)XXX。
1980年,中国制定了自己的字符集标准,全称为《信息交换用汉字编码字符集--*本集》,简称GB2312-80,一共收录了 7445 个字符,包括 6763 个汉字和 682 个其它符号。GB2312-80,简称为GB2312。
1993年,国际标准Unicode 1.1版本推出,收录中国大陆、台湾、日本及韩国通用字符集的汉字,总共有20,902个。中国大陆制定了等同于Unicode 1.1版本的“GB 13000.1-93”,简称为GB13000。
GB13000显然包含GB2312已有的文字和其他很多为包含的文字,如GB2312-80推出以后才简化的汉字(如“啰”),部分人名用字(如中国前总理***的“*”字),台湾及香港使用的繁体字,日语及朝鲜语汉字等。
GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification) ,中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订,国家技术监督局标准化司、电子工业部科技与质量监督司1995年12月15日联合以技监标函1995 229号文件的形式,将它确定为技术规范指导性文件。这一版的GBK规范为1.0版。
国家标准GB18030-2005《信息技术中文编码字符集》是我国继GB2312-1980和GB13000.1-1993之后最重要的汉字编码标准,是我国计算机系统必须遵循的*础性标准之一。 GB18030有两个版本:GB18030-2000和GB18030-2005。GB18030-2000是GBK的取代版本,它的主要特点是在GBK*础上增加了CJK统一汉字扩充A的汉字。GB18030-2005的主要特点是在GB18030-2000*础上增加了CJK统一汉字扩充B的汉字。
2.6 ANSI 编码
ANSI原意是指美国国家标准协会,但是在windows系统中,ANSI编码意思却代表“本地编码”。也就是说,在中国代表GBK,在台湾代表Big5,在日本代表JIS,所以windows编程中常说的ANSI字符串,就是指本地编码的字符串,在中国,就是一种DBCS,用1个和2个字节表示一个字符的编码。
为什么ANSI编码等同于本地编码?在微软的MSDN中找到一些说明:
早期,windows 中的英语和西欧字符集 code page 1252,是在ANSI草案*础上制定的,这个草案最后发展成ISO 8859-1,由此看来code page 1252 是早于ISO 8859-1标准的。因为这个,windows code page,通常被称为“ANSI code page”。
windows code page 有时候也指“系统活动代码页”,一个windows操作系统,总会有一个当前的活动代码页,也就是“本地代码页”。
可能因为这个原因,ANSI编码等同于本地编码。
不过也可以这么理解:ANSI编码本来只包含了英文编码,后来到了各国,在ANSI编码*础上扩展成了本地编码,所以ANSI编码也可以指本地编码,ANSI字符串也表示本地字符串。
ANSI也有自己的ASCII标准。但是我们看到的这个ANSI并不是特指ANSI的ASCII标准,这个应该指所有的本地化编码。
这个是微软的锅。一开始只有英文操作系统,用ANSI表示ANSI的Extend ASCII编码。但是到了欧洲就是ISO-8859-1编码,到中国应该是GBK编码,日本应该是JIS编码等等,为了把实际编码的差异隐藏起来,用所谓的ANSI编码来表示所有Windows系统上的地区化编码,然后操作系统自己做转换,不同的国家地区,就会对应不同的编码规范。
ANSI应该叫地区化编码,只出现在Windows系统中,就好像一种工厂模式,被Windows系统用来统一地区化编码的叫法。
2.7 Unicode、UCS
以上的编码都是本地化编码,一国之内还没有问题,但是要跨国,就不行了。比如汉字,在只有ISO-8859系列字符集的电脑上显示就只能是乱码了,要显示汉字,电脑上必须装GB2312或GBK的字符集。有没有一个字符集,能够包含全球所有的字符呢?这就是Unicode和UCS。
Unicode起源于1987年,施乐的 Joe Becker、苹果的 Lee Collins 和 Mark Davis 就开始研究能否创造一种全球通用的字符集。1988年,Joe Becker 发布了一个草案,提出了“Unicode”的概念,他解释说“‘Unicode’是一种唯一的、统一的、全球的编码”。后来,RLG、Sun、Microsoft、NeXT(乔布斯被赶出苹果后创建的公司)的人也都逐渐加入到Unicode工作组里。1991年1月3日,Unicode联盟组织成立,同年发布了Unicode1.0.
同时,ISO组织也在做同样的事情,创造一个全球统一的字符集(Universal Coded Character Set,简称UCS),1993年发布了标准ISO 10646-1。
后来,两个组织认识到,世界不需要两个不兼容的字符集,于是,开始合作。从Unicode2.0开始,开始采用和UCS相同的字库和字码。这样,两个项目仍都存在,并独立地公布各自的标准。但双方都同意保持两者标准的码表兼容,并紧密地共同调整任何未来的扩展。所以,现在说到UCS字符集,跟Unicode可以看成一回事。
Unicode编码包含两个层次:第一层定义字符的数值和第二层定义数值的实现方式。Unicode用数字 0x0~0x10FFFF 表示所有字符,所以最多可以容纳 1114112 个字符。数值的编码方式,也就是实现方式包括 UTF-8,UTF-16,UTF-32 三种。
有人会说,Unicode不是两个字节表示字符的码?为什么数值可以到0x10FFFF,这不21位,两个半字节还多了吗?其实,这是混淆了Unicode的数值定义和实现,这根本就是两个概念,Unicode到底用几个字节表示,取决于其实现方式是UTF-8,UTF-16,还是UTF-32.
比如,“汉字”对应的Unicode值是0x6c49和0x5b57,而编码实现是:
char data_utf8[]= {0xE6,0xB1,0x89,0xE5,0xAD,0x97}; //UTF-8编码
char16_t data_utf16[]= {0x6C49,0x5B57}; //UTF-16编码
char32_t data_utf32[]= {0x00006C49,0x00005B57}; //UTF-32编码
2.8 UTF-8
UTF,全称“Unicode Transformation Formats”。是Unicode的编码格式。
UTF-8是使用8-bit为单位,对Unicode进行编码的。特点是,对不同范围的字符使用不同长度的编码。
Unicode编码(十六进制)
|
UTF-8 字节流(二进制)
|
00000000 - 0000007F
|
0xxxxxxx
|
00000080 - 000007FF
|
110xxxxx 10xxxxxx
|
00000800 - 0000FFFF
|
1110xxxx 10xxxxxx 10xxxxxx
|
00010000 - 001FFFFF
|
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
00200000 - 03FFFFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
04000000 - 7FFFFFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-8 的编码规则很简单:
如果只有一个字节,那么最高的比特位为 0;如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。具体的表现形式为(xxx 就用来存储 Unicode 中的字符编号):
0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的;
110xxxxx 10xxxxxx:双字节编码形式;
1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式;
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式。
下面是一些字符的编码实例(绿色部分表示本来的 Unicode 编号):
字符 | N | æ | ⻬ |
Unicode 编号(二进制) | 01001110 | 11100110 | 00101110 11101100 |
Unicode 编号(十六进制) | 4E | E6 |
2E EC |
UTF-8 编码(二进制) | 01001110 | 11000011 10100110 | 11100010 10111011 10101100 |
UTF-8 编码(十六进制) | 4E | C3 A6 | E2 BB AC |
UTF-8编码的最大长度是6个字节。
对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同,用1个字节表示,首位为0。
对于0x80-0x7FF之间的字符,用2个字节表示,第一个字节前三位“110”为标志位,第二个字节前两位“10”为标志位。剩下的11位用来表示Unicode值(7FF最多11位)。
同样,UTF-8的3个字节,可以表示0x800-0xFFFF的Unicode(最多16位)。
UTF-8的4个字节,可以表示0x10000-0x001FFFFF的Unicode(最多21位)。
4个字节以内,已经包含了Unicode所有字符。
5、6个字节表示的已经是非Unicode编码范围,属于UCS-4 编码。早期UTF-8规范也可以达到6字节序列,不过2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中。
例:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx
10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001,
用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
例2:Unicode编码0x20C30在0x010000-0x10FFFF之间,使用用4字节模板了:11110xxx 10xxxxxx
10xxxxxx 10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 1100 0011
0000,用这个比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0
B0。
UTF-8有两个好处:
1. 1字节字符、2字节字符、3字节字符……的首字节标志位不同,这样可以很清楚的区分一个字节属于1字节字符还是2字节字符,如果一个字节流传输中出现错误,也不会错位,只影响部分字符,根据标志位,很容易找到下个正确字符。
2. 兼容ASCII码,英美字符用UTF-8可以一个字节表示,所以,www组织选用UTF-8作为推荐编码格式。2007年,在互联网上,UTF-8格式已经超过了ASCII码。
2.9 UTF-16
UTF-16以2字节为单位,等同于UCS-2.
Unicode编码(十六进制
|
UTF-16 字节流(二进制)
|
00000000 - 0000FFFF
|
xxxxxxxx xxxxxxxx
|
00010000 - 0010FFFF
|
110110yyyyyyyyyy 110111xxxxxxxxxx
|
Unicode值小于等于0xFFFF的,直接用两个字节表示,超过0xFFFF的,无法用两个字节表示。使用下面公式编码:
1. 计算 U’= U – 0x10000
2. 将U'写成二进制形式:yyyy yyyy yyxx xxxx xxxx
3. 加上标志位,1101 10yy yyyy yyyy 1101 11xx xxxx xxxx
可见,这是4个字节表示,2个6位标志位,20位有效位。因为U最大是0x10FFFF,所以U’最大是0xFFFFF,20位足够表示。
windows上默认的Unicode编码方式就是UTF-16,使用wchar_t表示。
2.10 UTF-32
UTF-32编码以4字节为单位。直接把Unicode值转为4字节二进制数就是其UTF-32编码。等同于UCS-4.
2.11 Base64
2.12 Big5
编码范围
|
符号类别
|
8140H-A0FEH
|
保留(用作造字区)
|
A140H-A3BFH
|
标点符号、希腊字母及特殊符号
|
A3C0H-A3FEH
|
保留(未开放用于造字区)
|
A440H-C67EH
|
常用汉字(先按笔划,再按部首排序)
|
C6A1H-C8FEH
|
保留(用作造字区)
|
C940H-F9D5H
|
非常用汉字(先按笔划,再按部首排序)
|
F9D6H-FEFEH
|
保留(用作造字区)
|
3 各种字符编码之间的关系
上面关于字符集和编码讲了许多概念,其实归类一下可以这么理解:
首先是单字节字符集:
1、最初美国ANSI发明了自己的编码ASCII,7-bit足够,这是标准ASCII。
2、标准ASCII码没有西欧国家拉丁文、英镑等字符,各公司、国家开始扩展,形成自己的扩展ASCII码字符集,各方混战,不过8-bit也就足够。
3、天下分久必合,ISO统一了8-bit字符集,叫做ISO 8859.
但是亚洲国家字符更多,一个字节远远不够,于是用多个字节表示,扩展形成本国字符集,中国GB系列,台湾Big5,日本JIS……,这些叫做多字节字符集(MBCS),windows中用双字节表示,也叫做(DBCS)。
以上字符都是群雄割据,各自为政,windows为了迎合大家需求,在哪个国家,默认编码就用那个国家的,不过后来不知怎么被误传位ANSI编码,其实ANSI怎么可能定义世界各国编码,不过可以理解成各编码都是在ANSI*础上扩展的,因为都兼容ANSI的标准ASCII码。
这时,ISO再次出手,和Unicode联盟携手打造了Unicode(UCS),意图一统江湖。Unicode确实包罗万象,涵盖了各国字符,于是流行世界。Unicode自身只定义了每个字符的数值,真正二进制编码格式却是UTF-8,UTF-16(UCS-2),UTF-32(UCS-4)。
至此,天下一统,但愿程序员的太平盛世到来了!
参考文章
字符编码的概念(UTF-8、UTF-16、UTF-32都是什么鬼) , 严长生.
字符编码,百度百科,2018.12。
ASCII,百度百科,2018.12.
计算机编码--2.ASCII与ANSI、ASCII扩展与IOS-8859-1,今夕何夕_1988,2018.7。
没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。