Python脚本也就是.py文件使用unicode编码作为脚本编码,编码格式是UTF8。
Unicode编码: 为世界上所有的文字或字符一个编码。这个编码在Unicode中叫做代码点(code point)。一个代码点通常表示为“U+FFFF”的形式。 所有代码点的集合,即Unicode字符集叫做UCS(Universal Character Set)。UCS-2 是UCS code in 2 octets,即用两个字节表示的UCS,其表示范围为:U+0000 ~ U+FFFF。为了表示更多字符还有UCS-4,即用4个字节表示的UCS,其表示范围为:U+00000000 ~ U+7FFFFFFF。UCS-4中U+00000000 ~ U+0000FFFF与UCS-2是重叠的,UCS-2是UCS-4的一个子集。
代码点是Unicode字符的内码,但如何存储这个代码点或者说如何存储这个内码呢?是直接存储这个代码点(内码)的值吗?目前有多种格式。
首先解释一下大端(Big Endian)和小端(Little Endian)。 这个概念是源于中央处理器CPU对多字节数据(如,int 4字节,char 2字节等)的处理方式(存储和传输)。一种是多字节数据的低位字节可以存储于内存的低位地址,高位字节依序存储于高位内存地址 - Little Endian(高位字节存储于高位地址);另一种则相反 - Big Endian(高位字节存储与低位地址)。如xe8af这个字符,高位字节是e8(11101000) 地位字节是af(10111111),存储于内存地址为0x00EFC77A和0x00EFC77B两个字节,如下所示:
Big Endian
0x00EFC77A 0x00EFC77B
11101000 10111111
--------------------------------------------
Little Endian
0x00EFC77A 0x00EFC77B
10111111 11101000
多字节编码的字符在内存/文件中存储时存在大小端的问题。
Unicode编码的存储方式有:UTF16/UTF32/UTF8 三种格式
UTF16:
UTF16直接存储UCS-2内码值和UCS-2是完全对应的,是一种多字节(2字节)编码。由于字节序的缘故,UTF-16包括三种:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian)。
UTF-16BE和UTF-16LE不难理解,而UTF-16就需要通过在文件开头以名为BOM(Byte Order Mark)的字符来表明文件是Big Endian还是Little Endian。BOM为U+FEFF这个字符。其实BOM是个小聪明的想法。由于UCS-2没有定义U+FFFE,因此只要出现 FF FE 或者 FE FF 这样的字节序列,就可以认为它是U+FEFF,并且可以判断出是Big Endian还是Little Endian。
UTF32:
类似于UCS-2 和UTF16的情况,只是字符用4个字节表示 和UCS-4完全对应,也存在Big Endian和Little Endian的问题。
UTF-8:
UTF-16和UTF-32的一个缺点就是它们固定使用两个或四个字节,很多字符编码中会有多余的00,导致传输效率降低。而RFC3629定义的UTF-8则解决了这个问题。UTF-8用1~4个字节来表示代码点,并且定义了每个字节的格式特征,因此是一种单字节编码方式,不存在Big Endian和Little Endian的问题。存储一个UTF-8字符时,需要将这个字符的Unicode内码,编码成字节数组,然后需要按照数组的顺序,一个一个字节写入,不用考虑字节序问题。其实本质是Big Endian。
表示方式如下:
UCS-2 (UCS-4) | 位序列 | 第一字节 | 第二字节 | 第三字节 | 第四字节 |
U+0000 .. U+007F | 00000000-0xxxxxxx | 0xxxxxxx | |||
U+0080 .. U+07FF | 00000xxx-xxyyyyyy | 110xxxxx | 10yyyyyy | ||
U+0800 .. U+FFFF | xxxxyyyy-yyzzzzzz | 1110xxxx | 10yyyyyy | 10zzzzzz | |
U+10000..U+1FFFFF | 00000000-000wwwxx- xxxxyyyy-yyzzzzzzz | 11110www | 10xxxxxx | 10yyyyyy | 10zzzzzz |
按照UTF-8标准:
(1)所有以0开始的字节,都与原来的ASCII码兼容,也就是说,0xxxxxxx不需要额外转换,就是我们平时用的ASCII码。
(2)所有以10开始的字节,都不是每个UNICODE的第一个字节,都是紧跟着前一位。例如:10110101,这个字节不可以单独解析,必须通过前一个字节来解析,如果前一个也是10开头,就继续前嗍。
(3)所有以11开始的字节,都表示是UNICODE的第一个字节,而且后面紧跟着若干个以10开头的字节。如果是110xxxxx(就是最左边的0的左边有2个1),代表后面还有1个10xxxxxx;如果是1110xxxx(就是最左边的0的左边有3个1),代表后面还有2个10xxxxxx;以此类推。 很明显,以11开头的,最左边的0左边有多少个1,那这个UCS的UTF-8的表示长度就有多少个字节。
注意:在微软window操作系统中,会给utf-8文件添加BOM【EF BB BF】(虽然不需要这么做),这并不是说明UTF-8需要字节序,而是仅仅表名该文件是utf-8编码的文件。
Reference:
https://blog.csdn.net/imxiangzi/article/details/77371228
https://blog.csdn.net/yo746862873/article/details/51780894
有关ANSI, ANSI 不是一种编码方式,而是使用字符编码的约定。只有windows在使用。ANSI的全称是 America National Standard Institute(美国国家标准协会)。微软在处理字符编码时收集了各个国家定义个各种字符编码集,如中国的GBK,台湾的Big5,韩国的EUC-KR,日本的Shift_JIS等等。每种编码在系统中定义了一个代码页(Windows code page) 来表示,每个代码页被赋予一个唯一的编码,如GBK 的code page 是936。通过设置Windows系统的Region and Language选项来指定系统当前使用的代码页。当Windows 程序在处理编码的时候可以通过当前活动代码页(active code page)调用相应的字符编码。这是微软解决系统本地化的方案。