1、Unicode和UTF-8

(1)Unicode是一种编码方式,把世界上所有的语言都实现了编码,如果直接应用在计算机上会导致极大的空间浪费,而utf-8解决了此中问题,所以得到了广泛的应用。

(2)utf-8是Unicode的一种实现,两者的编码在二进制上并不相同,具体见参考1中的链接

(3)utf-8最大的特点就是它是一种变长的编码方式,它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

(4)中文的GB2312也是一种中文的编码方式,但是与utf-8和unicode没有任何关系。

2、Python3 中的编码方式

(1)"The default encoding for Python source code is UTF-8, so you can simply include a Unicode character in a string literal". python3源码文件的默认编码方式是UTF-8,所以在python3的源码文件中可以直接使用所有的Unicode字符串,例如:

répertoire = "/tmp/records.log"
with open(répertoire, "w") as f:
    f.write("test\n")
print(len('❤️️'))
print(len('🌟'))

(2)UTF-8编码方式便于字符的存储和传输,但是在不同语言的内存中一般不使用UTF-8编码编码(据说:Go语言就是内部用utf8),原因是效率问题。在python3的内存中用的是unicode编码方式:

print("\N{BLACK CHESS KNIGHT}".encode())
str = '♞'
print(str.encode())
s = string_at(id(str), sys.getsizeof(str))
print(sys.getsizeof(str))
print(s.hex())

执行结果是:

b'\xe2\x99\x9e'
b'\xe2\x99\x9e'
76
0300000000000000408e9a08010000000100000000000000e245496c87c29da1a80000000000000000000000000000000000000000000000000000000000000000000000000000005e260000

分析:上述代码中"\N{BLACK CHESS KNIGHT}"和'♞'是同一个Unicode字符

打印结果的第一行和第二行的打印结果都是上述字符的UTF-8编码值,第三行是str对象所占用的字节数(python中一切皆为对象,所以此处的字符串对象长度为76个字节),第三行是str对象在内存中的存储情况在靠近尾部的位置可以找到'♞'的存储值为'5e26',和下图中Unicode编码对照表中的值是相同的,只不过内存中的值是小端存储,所以可以确定python3内存中字符是用unicode编码的。Java内存中字符的表现形式也是Unicode编码。

0061    'a'; LATIN SMALL LETTER A
0062    'b'; LATIN SMALL LETTER B
0063    'c'; LATIN SMALL LETTER C
...
007B    '{'; LEFT CURLY BRACKET
...
2167    'Ⅷ'; ROMAN NUMERAL EIGHT
2168    'Ⅸ'; ROMAN NUMERAL NINE
...
265E    '♞'; BLACK CHESS KNIGHT
265F    '♟'; BLACK CHESS PAWN
...
1F600   '😀'; GRINNING FACE
1F609   '😉'; WINKING FACE
...

查看系统大小端的方法:

if (ByteOrder.nativeOrder()==ByteOrder.BIG_ENDIAN){
    System.out.println("big endian");
}else {
    System.out.println("little endian");
}

3、Python3 encode和decode方法:Built-in Types

bytes.decode:把指定编码方式(默认是utf-8)的二进制序列解码为Unicode字符。其参数为bytes二进制序列的编码方式---知道其编码方式才能解码

str.encode:把python中Unicode字符转化为指定的编码,默认是utf-8。其参数是要实现的编码方式

#Return a string decoded from the given bytes. Default encoding is 'utf-8'.
bytes.decode(encoding="utf-8", errors="strict")

#Return an encoded version of the string as a bytes object. Default encoding is 'utf-8'. 
str.encode(encoding="utf-8", errors="strict")

4、emoji表情符号也是Unicode中的一个符号,与'a','1'等字符相同,而且Unicode字符集也在不断的更新中

emoji及其code point:https://unicode.org/emoji/charts/full-emoji-list.html#1f3f4_e0067_e0062_e0065_e006e_e0067_e007f

UTF-16编码和unicode code point:https://zh.wikipedia.org/wiki/UTF-16

UTF-8编码和unicode code point:https://zh.wikipedia.org/wiki/UTF-8

组合emoji表情符:Unicode: Behind the Curtain

python3 代码,code point转utf-16和utf-8

注:utf-8没有字节序的问题

# code point:U+1F600 emoji:😀
# 注:在mac中实际测试发现\x3d会被替换为=,这里手动做了替换
# 若转化utf-16不指定字节序,则结果中会自带一个字节序:在UTF-16文件的开首,都会放置一个U+FEFF字符作为Byte Order Mark(UTF-16 LE以 FF FE 代表,UTF-16 BE以 FE FF 代表)
>>> '\U0001f600'.encode(encoding="utf-16")
b'\xff\xfe\x3d\xd8\x00\xde'
>>> '\U0001f600'.encode(encoding="utf-16be")
b'\xd8\x3d\xde\x00'
>>> '\U0001f600'.encode(encoding="utf-16le")
b'\x3d\xd8\x00\xde'
>>> '\U0001f600'.encode(encoding="utf-8")
b'\xf0\x9f\x98\x80'
>>>

5、code point(码位) 和 code unit(码元)

(1)code point

(2)code unit

6、参考:

(1)吐血总结,彻底明白 python3 编码原理

(2)Unicode HOWTO

(3)Unicode Character Categories

(5)为什么 UTF-8 不存在字节序的问题?