- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
假设我在 Python 中有一个字符串:
>>> s = 'python'
>>> len(s)
6
现在我像这样编码
这个字符串:
>>> b = s.encode('utf-8')
>>> b16 = s.encode('utf-16')
>>> b32 = s.encode('utf-32')
我从上面的操作中得到的是一个字节数组——也就是说,b
、b16
和 b32
只是字节数组(当然,每个字节都是 8 位长)。
但我们对字符串进行了编码。那么这是什么意思?我们如何将“编码”的概念附加到原始字节数组?
答案在于这些字节数组中的每一个都是以特定方式生成的。让我们看看这些数组:
>>> [hex(x) for x in b]
['0x70', '0x79', '0x74', '0x68', '0x6f', '0x6e']
>>> len(b)
6
这个数组表示对于每个字符我们有一个字节(因为所有字符都在 127 以下)。因此,我们可以说将字符串“编码”为“utf-8”会收集每个字符对应的代码点并将其放入数组中。如果代码点不能放在一个字节中,那么 utf-8 会占用两个字节。因此 utf-8 消耗尽可能少的字节数。
>>> [hex(x) for x in b16]
['0xff', '0xfe', '0x70', '0x0', '0x79', '0x0', '0x74', '0x0', '0x68', '0x0', '0x6f', '0x0', '0x6e', '0x0']
>>> len(b16)
14 # (2 + 6*2)
在这里我们可以看到,“编码为 utf-16”首先将两个字节的 BOM (FF FE
) 放入字节数组中,然后,对于每个字符,它将两个字节放入大批。 (在我们的例子中,第二个字节总是零)
>>> [hex(x) for x in b32]
['0xff', '0xfe', '0x0', '0x0', '0x70', '0x0', '0x0', '0x0', '0x79', '0x0', '0x0', '0x0', '0x74', '0x0', '0x0', '0x0', '0x68', '0x0', '0x0', '0x0', '0x6f', '0x0', '0x0', '0x0', '0x6e', '0x0', '0x0', '0x0']
>>> len(b32)
28 # (2+ 6*4 + 2)
在“utf-32 编码”的情况下,我们首先放入 BOM,然后为每个字符放入四个字节,最后将两个零字节放入数组中。
因此,我们可以说“编码过程”为字符串中的每个字符收集 1、2 或 4 个字节(取决于编码名称),并在它们前面添加和追加更多字节以创建最终的字节结果数组。
现在,我的问题:
b
、b16
和b32
的内存表示实际上是一个字节列表。字符串的内存表示是什么?字符串在内存中究竟存储了什么?encode()
时,每个字符对应的代码点被收集(代码点对应于编码名称)并放入一个数组或字节中。当我们执行 decode()
时到底发生了什么?最佳答案
首先,UTF-32是一个4字节的编码,所以它的BOM也是一个四字节的序列:
>>> import codecs
>>> codecs.BOM_UTF32
b'\xff\xfe\x00\x00'
并且由于不同的计算机体系结构以不同方式处理字节顺序(称为 Endianess ),因此 BOM 有两种变体,小端和大端:
>>> codecs.BOM_UTF32_LE
b'\xff\xfe\x00\x00'
>>> codecs.BOM_UTF32_BE
b'\x00\x00\xfe\xff'
BOM 的目的是将该订单传达给解码器;阅读 BOM,您知道它是大端还是小端。因此,UTF-32 字符串中的最后两个空字节是最后编码字符的一部分。
UTF-16因此,BOM 很相似,因为有两种变体:
>>> codecs.BOM_UTF16
b'\xff\xfe'
>>> codecs.BOM_UTF16_LE
b'\xff\xfe'
>>> codecs.BOM_UTF16_BE
b'\xfe\xff'
默认使用哪一个取决于您的计算机架构。
UTF-8根本不需要 BOM; UTF-8 每个字符使用 1 个或多个字节(根据需要添加字节以编码更复杂的值),但这些字节的顺序在标准中定义。 Microsoft 认为无论如何有必要引入 UTF-8 BOM(因此其记事本应用程序可以检测 UTF-8),但由于 BOM 的顺序从不改变,因此不鼓励使用它。
至于unicode字符串,Python存储的是什么;实际上在 Python 3.3 中发生了变化。在 3.3 之前,在 C 级别内部,Python 存储 UTF16 或 UTF32 字节组合,这取决于 Python 是否使用宽字符支持编译(参见 How to find out if Python is compiled with UCS-2 or UCS-4?,UCS-2 本质上 UTF- 16 和 UCS-4 是 UTF-32)。因此,每个字符占用 2 或 4 个字节的内存。
从 Python 3.3 开始,内部表示使用表示字符串中所有字符所需的最小 字节数。对于纯 ASCII 和 Latin1 可编码文本,使用 1 个字节,用于 BMP 的其余部分使用 2 个字节,并使用包含超过 4 个字节的字符的文本。 Python 根据需要在格式之间切换。因此,在大多数情况下,存储变得更加高效。有关详细信息,请参阅 What's New in Python 3.3 .
我可以强烈建议您阅读 Unicode 和 Python:
关于 python 3 : Demystifying encode and decode methods,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13469591/
有人可以为我揭开这条线的神秘面纱吗? 它是 javascript 并且工作正常,我只是不明白代码背后的确切逻辑。也许将代码分成几行或用 c# 或 delphi 编写代码以进行“比较”会有所帮助。 (我
假设我在 Python 中有一个字符串: >>> s = 'python' >>> len(s) 6 现在我像这样编码这个字符串: >>> b = s.encode('utf-8') >>> b16
我是一名优秀的程序员,十分优秀!