因此,我试图理解将十六进制转义序列转换为整数时所涉及的数学。
因此,如果我有字符串“Ô,那么当我执行"Ã".encode('utf-8')
时,我会得到一个像"\xc3"
这样的字节字符串。 ord("Ã")
是195。数学是16 * 12 + 3,即195。一切都说得通。
但是,如果我有字符“é”,那么utf8编码的十六进制转义序列为"\xc3\xa9
-而ord("é")
为233。如何执行此计算? (a9本身是169,因此显然不是加法。)
与此'Ĭ'.encode('utf-8')
类似。这产生b'\xc4\xac'
。 ord('Ĭ')
是300。
有人可以解释这里涉及的数学吗?
答案 0 :(得分:2)
来自文档:
ord(c)
给出一个表示一个Unicode字符的字符串,返回一个 表示该字符的Unicode代码点的整数。对于 例如,ord('a')返回整数97,而ord('€')(欧元符号) 返回8364。这是chr()的反函数。
ord
返回的是字符的Unicode代码点-大致来说,该数字使您可以在Unicode已知的大量字符中识别字符。
当您使用UTF-8编码字符时,将用一个字节序列表示该字符,该字节序列与Unicode代码点没有直接关系。可能会有一些巧合,主要是对于以一个字节的序列表示的ASCII字符,但这将对所有其他“奇异”字符都失败。
看看The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)和the wikipedia page about UTF-8。
答案 1 :(得分:2)
UTF-8是根据一些通用设计原则/约束设计的。了解这些设计原则对于理解UTF-8的编码算法为何如此重要至关重要。
UTF-8编码的工作方式如下:
0
位开头的单个八位字节。110
,1110
或11110
开头,其中1
位的位数表示长度多八位位组序列的长度,即以八位组1110xxxx
开头的多八位位组序列的长度为3个八位位组。10
开头。这里是一个示例:A
具有Unicode代码点U + 0041。由于它是ASCII字符,因此将简单地以与ASCII相同的方式进行编码,即二进制01000001
。
欧元符号€
的Unicode代码点为U + 20AC。由于它不是ASCII字符,因此需要将其编码为多字节的编码序列。二进制的十六进制0x20AC为10000010101100,因此需要14位来表示。
一个两字节的序列如下所示:110xxxxx 10xxxxxx
,因此它只给我们11位。因此,我们需要一个三字节的序列,如下所示:1110xxxx 10xxxxxx 10xxxxxx
。这给了我们16位,这超出了我们的需要。现在,将代码点的零扩展二进制表示形式打包到x
es中:
11100010 10000010 10101100
^^^^00xx ^^xxxxxx ^^xxxxxx
此位串的十六进制表示形式为0xE2 0x82 0xAC
。
注意:通过将代码点进一步零扩展,也可以将其编码为四个八位字节的序列。这称为超长编码,UTF-8规范不允许使用。编码必须尽可能短。
有一种称为 Modified UTF-8 的编码,该编码不是将ASCII NUL编码为ASCII,而是将其编码为 overlong 多字节序列。这样,MUTF-8字符串可以包含ASCII NUL字符,而从未包含0x00
空八位字节,因此可以由期望字符串以空值终止的环境进行处理。
答案 2 :(得分:0)
"é"
的ASCII编码为0xe9
,等于十进制的233。
为方便起见,示例代码
for n in range(256):
print(n,hex(n),chr(n))
答案 3 :(得分:0)
所以,我认为我只是把它总结一下,然后在我从SO中学到很多智慧之前,将我没有理解的数学问题的答案发布出来。
第一个问题“é”在使用utf8编码时会产生"\xc3\xa9"
,其中ord("é")
返回233
。显然,233不是195(c3的十进制表示)和169(a9的同上)的总和。那是怎么回事?
“é”具有对应的unicode点U+00E9
。十六进制e9
的十进制值为233。这就是ord("é")
的全部含义。
那么,结果如何变成"\xc3\xa9"
?
正如JörgW Mittag解释和演示的那样,在utf8中,所有非ASCII都被“编码为多八位字节序列” 。
233的二进制表示形式是11101001
。由于这是非ASCII格式,因此需要打包成两个八位字节的序列,按照约尔格的说法,它将遵循以下模式:
110xxxxx 10xxxxxx
(固定的110和10为第一个八位位组保留5位,第二个八位位组保留6位-总共11位)。
因此,此模式将233的8位二进制表示形式替换为xx部分...由于有11位可用,我们只需要8位,因此我们用另外3个000
填充了8位,(即00011101001
)。
^^^00011 ^^101001
(000
,后跟我们的233的8位表示形式)
11000011 10101001
(以两个八位字节的顺序插入的233的二进制表示形式)
11000011
等于十六进制c3
,而10101001
等于a9
-换句话说,它匹配原始序列"\xc3\xa9"
类似的字符“Ĭ”演练:
'Ĭ'.encode('utf-8')
产生b'\xc4\xac'
。 ord('Ĭ')
是300。
因此,该字符的unicode点再次是U+012C
,其十进制值为300((1 * 16 * 16)+(2 * 16 * 1)+(12 * 1))-因此ord部分。
同样,二进制表示形式300是9位100101100
。因此,再次需要模式110xxxxx 10xxxxxx
的两个八位字节的序列。再一次,我们用几个0
填充它,以便达到11位(00100101100
)。
^^^00100 ^^101100
(00
后跟我们的9位表示300)
11000100 10101100
(在两个八位字节序列中插入的300的二进制表示形式)。
11000100
对应于c4
的十六进制,10101100
对应于ac
-换句话说b'\xc4\xac'
。
感谢大家在此方面的帮助。我学到了很多东西。