我们在python字符编码的时候,通常可以看到这样的输出:
>>> '好'.encode()
b'\xe5\xa5\xbd'
这里的3个十六进制数值是怎么来的,这里做一个解析。“好”字的Unicode编码号是
>>> ord('好')
22909
uft-8编码的规则是
0-127的用一个字节表示,首位为0
128-2047的用2个字节表示,第一个字节首位是110,第二个字节首位是10
2048-65535的用3个字节表示,第一个字节首位是1110,第二个,第三个字节首位都是10
65536及以上的用4个字节表示,第一个字节首位是11110,第二个,第三个,第四个字节首位都是10
22909处于2048到65535之间,所以这个编码的结果是3个字节,
我们将其转换为二进制然后填满这几个字节余下的位就可以了,下面通过笔算来实现这个过程。展示:
f'{n:0>16b}'这样的代码,以此为例解释,三个字节的字符,由于固定的首位分别是1110,10和10,三个字节总共24位,因此需要填充的字节数量长度是24-4-2-2=16,在转换这个Unicode编码为二进制的时候就把不足16位的前面全部充满0做填充,以便于后面的切割操作。
def GetHex(s: str):
if s.__len__() != 1:
return False
n = ord(s) # 得到字符的unicode号
if n in range(128): # Unicode号在0-127之间的
# 结果是ASCII,只有一位
return hex(n)
elif n in range(128, 2049): # Unicode号在128-2049之间的字符
# 由2个字节组成,开头分别是110和10
bn = f'{n:0>11b}' # 需要填充的二进制长度为11位
b1 = f'110{bn[:-6]}' # 取倒数第6位之前的拼接第一个字节二进制
b2 = f'10{bn[-6:]}' # 取倒数第6位以后的拼接第二个字节二进制
return f'{hex(int(b1,2))} {hex(int(b2,2))}'
elif n in range(2048, 65536): # Unicode号介于2048到65536的
# 由3个字节组成,开头分别是1110,10,10
bn = f'{n:0>16b}' # 需要填充的二进制长度为16位
b1 = f'1110{bn[:-12]}' # 取倒数12位之前的拼接最右边的二进制
b2 = f'10{bn[-12:-6]}' # 取倒数12到倒数第6位之间的拼接中间二进制
b3 = f'10{bn[-6:]}' # 取倒数6位拼接最左边的二进制
return f'{hex(int(b1,2))} {hex(int(b2,2))} {hex(int(b3,2))}'
elif n > 65535: # Unicode号大于65535的
# 由4个字节组成,开头分别是11110,10,10,10
bn = f'{n:0>21b}' # 需要填充的二进制长度为21位
b1 = f'11110{bn[:-18]}' # 取倒数18位之前的拼接第一个字节二进制
b2 = f'10{bn[-18:-12]}' # 取倒数第18位到倒数第12位之间的拼接第二个字节二进制
b3 = f'10{bn[-12:-6]}' # 取倒数第12位到倒数第6位之间的拼接第三个字节二进制
b4 = f'10{bn[-6:]}' # 取倒数第6位以后的拼接第四个字节二进制
return f'{hex(int(b1,2))} {hex(int(b2,2))} {hex(int(b3,2))} {hex(int(b4,2))}'