大部分程序员都会认为:
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.
ASCII码如下图:
一共128个字符:
0-31
:为控制字符,non-printable23-127
:为可显示字符,printable如12
是提醒printer打印机换页的,当打印机遇到这个控制字符00001100
的时候,会使用一张新的纸
如0
是终止符,就是我们C语言常见\0
NULL
如65
是uppercase的A
细心的你可能会发现ASCII只使用了一个byte中的7个bits,还有128-255
这128个空间没有使用
一开始互联网不普及,美国等使用英文国家自己使用ASCII足够了。但随着互联网的普及,世界上那么多的国家使用那么多的语言,ASCII不够了
ANSI不是指的一种特定的encoding,而是各个国家在ASCII的基础上,基于还没有使用的另外128个空间,对ASCII扩充,本地locale的结果
如在简体中文操作系统中ANSI对应就是GB2312
:
同理,日文操作系统下,ANSI就是JIS编码
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 Mark
BOM,FE FF
大端,FF FE
小端需要交换下位置
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的优势:
\0
,那么输出字节流里也不含\0
,不会额外引入\0
UTF-8可以使用1-4bytes表示所有1112064个有效的code points
UTF-8详细是怎么编码的,如下:
把开始的0去掉,如果code point的位数在7位,使用一个byte,在11位以内,2个bytes,如上同理类似。一般常用的CJK语言中日韩是使用3个字节
可以感受到UTF-8的最小逻辑单元是一个字节,对于那些超过1个字节WORD/INTERER等类型才会有字节序问题
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-Type
header
web server一开始是不知道HTML page编码的,开始以一种特定编码(可能UTF-16)尝试,因为大部分编码都兼容ASCII,又meta放在HTML page的最上方,所以能很快的获取正确的编码方式(UTF-8),HTML page后面就不用以错误的UTF-16编码方式解析了,效率会很高
如果HTML page中没有指定这个,web server会根据语言统计特点(如频度等)去猜
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