关于字符集和编码你应该知道的

1 Introduction

大部分程序员都会认为:

plain text = ascii = character,如我们使用的A字符,就是一个字节(8bits)。Unicode字符集占用2个字节,所以可以表示65536个字符

其实,都不太对。

主要介绍ASCII、ANSI、Unicode和UTF-8,并想让大家培养一个意识:
当谈及一个sting字符串的时候,不知道它的编码方式是没有意义的
It does not make sense to have a string without knowing what encoding it uses.

2 ASCII

ASCII码如下图:

一共128个字符:

  • 0-31:为控制字符,non-printable
  • 23-127:为可显示字符,printable

12是提醒printer打印机换页的,当打印机遇到这个控制字符00001100的时候,会使用一张新的纸

0是终止符,就是我们C语言常见\0 NULL

65是uppercase的A

3 ANSI

细心的你可能会发现ASCII只使用了一个byte中的7个bits,还有128-255这128个空间没有使用

一开始互联网不普及,美国等使用英文国家自己使用ASCII足够了。但随着互联网的普及,世界上那么多的国家使用那么多的语言,ASCII不够了

ANSI不是指的一种特定的encoding,而是各个国家在ASCII的基础上,基于还没有使用的另外128个空间,对ASCII扩充,本地locale的结果

如在简体中文操作系统中ANSI对应就是GB2312

  • 一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,可以组成大约7000多个简体汉字

同理,日文操作系统下,ANSI就是JIS编码

4 Unicode

a letter字符会map到一个code point,最新版Unicode的code point space是0(hex) to 10FFFF(hex),有0-10(16进制),10进制就是0-16共17个planes,每个plane下面又有65536个code points

Plane 0是Basic Multilingual Plane (BMP), 包含我们最常用的字符,剩于的作为补充supplementary planes

下图可以对code point space有个直观的感受:

好的,也就是Unicode字符集不止2个字节,可表示的字符数远不止65536个


继续说编码,为什么会有UTF-8、UTF-16这类东西?

字符串Hello:对应的code point如下:

U+0048 U+0065 U+006C U+006C U+006F

我们2个字节2个字节存,内存中可能如下存储,编码encoding就是指存储方式:

00 48 00 65 00 6C 00 6C 00 6F

当然这时候涉及字节序endianness问题(和CPU相关),内存中也可能如下存储:

48 00 65 00 6C 00 6C 00 6F 00

上面就是现在UTF-16,16指的是16bits(2字节),2种分别是BE和LE,对应着大端和小端,所以每个UTF-16编码的string,需要在开头引入FE FF作为Unicode Byte Order MarkBOM,FE FF大端,FF FE小端需要交换下位置

5 UTF-8

UTF-16没有UTF-8流行是有原因的,如上,UTF-16存储ASCII字符也是用了2个字节,同时额外引了00这个\0字符,在很多C库中\0意味着终止,这干扰了库的正常工作

UTF-8,可以解决上述问题,stringHello的UTF-8编码为:48 65 6C 6C 6F,兼容了ASCII

总结UTF-8的优势:

  1. UTF-8兼容ASCII
  2. 8指8bits,即一个byte,基本单元是一个字节,所以不存在字节序问题
  3. 如果输入的字符串不包含\0,那么输出字节流里也不含\0,不会额外引入\0
  4. 编码短,节省空间

UTF-8可以使用1-4bytes表示所有1112064个有效的code points

UTF-8详细是怎么编码的,如下:

把开始的0去掉,如果code point的位数在7位,使用一个byte,在11位以内,2个bytes,如上同理类似。一般常用的CJK语言中日韩是使用3个字节

可以感受到UTF-8的最小逻辑单元是一个字节,对于那些超过1个字节WORD/INTERER等类型才会有字节序问题

6 Others

HTML通常会被http请求发送,header中有Content-Type: text/html; charset="UTF-8",这个是在http请求头里的,不是在HTML里面的,浏览器或web server从header中获取content的type信息,那么http的header又从哪里获取发送的HTML page的encoding?

HTML中使用如下meta(meta用于描述页面):




equiv = equivalent,等同的意思,表明这个meta就决定了http的Content-Typeheader

web server一开始是不知道HTML page编码的,开始以一种特定编码(可能UTF-16)尝试,因为大部分编码都兼容ASCII,又meta放在HTML page的最上方,所以能很快的获取正确的编码方式(UTF-8),HTML page后面就不用以错误的UTF-16编码方式解析了,效率会很高

如果HTML page中没有指定这个,web server会根据语言统计特点(如频度等)去猜

7 References

https://www.fileformat.info/info/unicode/utf8.htm
https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
https://stackoverflow.com/questions/700187/unicode-utf-ascii-ansi-format-differences
http://www.imkevinyang.com/2009/02/%E5%AD%97%E7%AC%A6%E7%BC%96%E8%A7%A3%E7%A0%81%E7%9A%84%E6%95%85%E4%BA%8B%EF%BC%88ascii%EF%BC%8Cansi%EF%BC%8Cunicode%EF%BC%8Cutf-8%E5%8C%BA%E5%88%AB%EF%BC%89.html
http://blog.sciencenet.cn/blog-3134052-1074221.html
http://www.babelstone.co.uk/Unicode/HowMany.html
https://www.zhihu.com/question/24572900
https://stackoverflow.com/questions/3833693/isn-t-on-big-endian-machines-utf-8s-byte-order-different-than-on-little-endian
https://en.wikipedia.org/wiki/Code_point
https://en.wikipedia.org/wiki/Plane_(Unicode)
https://unicode-table.com/en/#control-character
https://en.wikipedia.org/wiki/Endianness
https://en.wikipedia.org/wiki/UTF-8
https://stijndewitt.com/2014/08/09/max-bytes-in-a-utf-8-char/
https://tools.ietf.org/html/rfc3629
https://stackoverflow.com/questions/9533258/what-is-the-maximum-number-of-bytes-for-a-utf-8-encoded-character

你可能感兴趣的:(UTF-8,字符集,编码)