如何根据字节序列计算整数

时间:2019-03-10 08:14:53

标签: python-3.x utf-8 hex

因此,我试图理解将十六进制转义序列转换为整数时所涉及的数学。

因此,如果我有字符串“Ô,那么当我执行"Ã".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。

有人可以解释这里涉及的数学吗?

4 个答案:

答案 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的编码算法为何如此重要至关重要。

  1. 向后兼容ASCII:每个ASCII字符在ASCII和UTF-8中应具有相同的编码。
  2. 非ASCII字符的可检测性:在非ASCII字符的多八位字节编码序列中,不应出现将成为ASCII字符有效编码的八位字节。
  3. 长度编码:多字节编码序列的长度应在第一个八位字节中编码,这样我们才能在读取整个多字节编码序列之前知道它将有多长。同样,对于人类来说,很容易确定多字节编码序列的长度。
  4. 回退/自动检测:采用高度流行的8位编码(例如ISO8859-15,Windows-1252)之一的文本高度不太可能包含有效的UTF-8 multi序列-octet编码序列,因此可以很容易地检测到这种编码,反之亦然。
  5. 自同步:您可以在UTF-8流中间的任何地方开始解码,最多需要您直到下一个ASCII字符或下一个多八位位组编码序列的开始,才能开始解码有效字符。如果您可以在流中向后导航,则最多需要备份3个八位位组才能找到有效的起点。
  6. 排序顺序:按八位字节排序UTF-8流将自动按代码点产生排序顺序,而无需解码该流。

UTF-8编码的工作方式如下:

  • 任何ASCII字符都以与ASCII相同的方式编码,即以一个0位开头的单个八位字节。
  • 任何非ASCII字符都被编码为多字节序列。
  • 多八位位组编码序列的第一个八位位组以位模式110111011110开头,其中1位的位数表示长度多八位位组序列的长度,即以八位组1110xxxx开头的多八位位组序列的长度为3个八位位组。
  • 属于多八位位组序列的任何其他八位位组都以位模式10开头。
  • Unicode码点被编码为多字节编码序列的非固定位。

这里是一个示例: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 ^^101001000,后跟我们的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 ^^10110000后跟我们的9位表示300)

11000100 10101100(在两个八位字节序列中插入的300的二进制表示形式)。

11000100对应于c4的十六进制,10101100对应于ac-换句话说b'\xc4\xac'

感谢大家在此方面的帮助。我学到了很多东西。