python3默认使用什么编码_请教, Python3 的 str 底层是用什么编码储存的?

12

2016-01-03 00:16:10 +08:00 heart_neue_red.png?v=16ec2dd0a880be6edda1e4a2e35754b3 1

我去,原来如此复杂。

感谢楼上几位给出的资料和方法。

python 源码中这个文件有 15665 行,实在是让人望而生畏。

@ruoyu0088 提到编码是自动选择的,我结合读文档的理解和一些测试,

再次进行了一遍求证,最后得到的结论是:

python3 的字符串是根据输入确定编码,在 Latin1 , UTF16 、 UTF32 之间进行切换。

验证的过程是这样的:

1. 首先是 ucs2(utf16) 的情况 (据我所知 ucs2 与 u16 等价, ucs4 与 u32 等价,不知是否正确)

In [60]: a = '中文'

In [61]: binascii.hexlify(ctypes.string_at(id(a), a.__sizeof__()))

Out[61]: b'010000003094e51d0200000056f1a772a8000000f447c7000000000000000000020000002d4e87650000'

In [62]: binascii.hexlify('中文'.encode('utf-16'))

Out[62]: b'fffe2d4e8765'

我们可以看到,“中文”两个字在编码为 utf16 之后首先是 fffe 这个头部,随后的 2d4e 8765 分别对应两个字,这与从内存中弄到的字符串形态是相同的。

2. 那么我们在文本中加入一个 UCS2 表示不了的字符串呢?会怎么样?

In [64]: a = '\U000a1ffa 中文'

In [65]: binascii.hexlify(ctypes.string_at(id(a), a.__sizeof__()))

Out[65]: b'010000003094e51d03000000220bc0a8b000000000000000000000000000000000000000fa1f0a002d4e00008765000000000000'

我们可以看到, 2d4e 变成了 2d4e0000 , 8765 变成了 87650000 ,最后是 8 个 0 (一个 UCS4 字符)结尾。

而 fa1f0a00 是 000a1ffa 在内存中的形式(从右向左,每一个字节——即俩 HEX ——逐个倒装)

其实我觉得奇怪的地方在于, python 其实记录了文本的长度,为啥坚持 C 风格的字符串(末尾加\0 )?

看看这个字符串 encode 后的样子吧!

In [66]: binascii.hexlify('\U000a1ffa 中文'.encode('utf-32'))

Out[66]: b'fffe0000fa1f0a002d4e000087650000'

In [67]: binascii.hexlify('\U000a1ffa 中文'.encode('utf-8'))

Out[67]: b'f2a1bfbae4b8ade69687'

头部变成了 fffe0000 其他都一致。

3. 最后再看看单字节的字符串

In [68]: a = "\x9a\x9b"

In [69]: binascii.hexlify(ctypes.string_at(id(a), a.__sizeof__()))

Out[69]: b'010000003094e51d02000000b9bdd189a4000000000000000000000000000000000000009a9b00'

=====

In [70]: a = "\x9a\x9b 中"

In [71]: binascii.hexlify(ctypes.string_at(id(a), a.__sizeof__()))

Out[71]: b'010000003094e51d03000000a4036e4ba8656164f44dc7000000000000000000030000009a009b002d4e0000'

=====

In [72]: a = "\x9a\x9b 中\U000a1ffa"

In [73]: binascii.hexlify(ctypes.string_at(id(a), a.__sizeof__()))

Out[73]: b'010000003094e51d04000000776e9375b000005a000000000000000000000000000000009a0000009b0000002d4e0000fa1f0a0000000000'

果然不出所料。

说起来\U0000000 是一个比较少用的语法,专门用来转义 UCS4 的。

要不是前段时间搞了 tinyre 这个项目,我肯定是弄不出这样的字符的……

顺便宣传一下在下最近这个项目,一个正则引擎: https://github.com/fy0/tinyre

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值