作者os653 (allstar)
看板Python
标题[问题] unicode->bytes->unicode的编码
时间Thu Sep 26 00:00:09 2013
想让 python2 跟 python3 的程式交换资料,但在 unicode 这部分遇到点麻烦
请问有没有 codec 能符合下列条件?
1. 能将字元范围从 \u0000 ~ \uFFFF 的 unicode 字串转成 bytes 再转回 unicode
且不会出错或遗失资料
2. 在 python2 和 python3 下,同样的 unicode 字串编码後得到的 bytes 结果相同
3. 在 python2 和 python3 下,同样的 bytes 解码後得到的 unicode 结果相同
4. 速度快且编码後的 bytes 体积小
举例来说,u'\ud800\udc00' 这段字串因为不是合法的 unicode
编解码上就会出现各种奇怪的问题,不晓得有没有解?
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 114.46.145.28
1F:推 AstralBrain:只想得到utf32 体积会变两倍大就是了XD 09/26 00:27
utf32 不行耶...
python2
>>> u'\ud800\udc00'.encode('utf32')
'\xff\xfe\x00\x00\x00\x00\x01\x00'
python3
>>> u'\ud800\udc00'.encode('utf32')
b'\xff\xfe\x00\x00\x00\xd8\x00\x00\x00\xdc\x00\x00'
2F:推 AstralBrain:咦 我的python 2.7.4和3.3.1都是出现下面那串 09/26 00:45
应该是字元宽度的关系,windows python2 预设 ucs2,python3 则是 ucs4
3F:推 AstralBrain:是说不合法字元出现未定义行为也不意外.. 09/26 00:49
4F:→ uranusjr:utf8 就可以了, 因为 Python 的 UTF-8 编码无视保留区... 09/26 00:51
5F:→ uranusjr:我在 OS X 上的结果和原 po 一样, 应该是某个版本 fix 过 09/26 00:55
6F:推 AstralBrain:我把u'\ud800\udc00'先encode('utf8')再decode回来 09/26 00:56
7F:→ AstralBrain:结果变成u'\U00010000' 09/26 00:57
所以很难搞...基本上那转换结果也不能说错,可是就会出现
s.encode('utf-8').decode('utf-8') != s 这种不直觉的东西
8F:→ uranusjr:喔我发现 3.3 的 utf8 把 surrogate 挡掉了, GG XD 09/26 00:58
9F:→ uranusjr:这样看来是不可能了, 自己土炮一个转换表吧 09/26 01:00
土炮有效能问题,自从用了 python,就再也没再装过 c++ 了 XD
目前是 utf-7 顶着用,他们似乎不认为 utf-7 编的是文字所以没挡 surrogate
不过遇到像上面举的那个例子一样会爆炸 orz...
10F:推 AstralBrain:翻了文件发现有unicode_internal这怪东西可以用 09/26 01:12
11F:→ AstralBrain:试试看u'\ud800\udc00'.encode('unicode_internal') 09/26 01:12
这个一样有可能会出现不直觉的结果
python3
>>> s = u'\ud800\udc00'
>>> s.encode('unicode_internal')
b'\x00\xd8\x00\xdc'
>>> s.encode('unicode_internal').decode('unicode_internal')
'\U00010000\x27'
>>> s.encode('unicode_internal').decode('unicode_internal') == s
False
12F:推 AstralBrain:又是OS的差异吗orz 那我就没办法了XD 09/26 01:31
其实跟 OS 没啥关系啦...
13F:→ uranusjr:其实我突然有个疑问, 你是要拿来干什麽用... 09/26 10:49
14F:→ uranusjr:如果只是要存起来或传输的话, 直接把 Unicode string 09/26 10:50
15F:→ uranusjr:pickle 起来不行吗? 09/26 10:50
是要拿来传输没错,想要在 python3 使用一些只有 python2 才有的 module
pickle 在 python2 跟 python3 本来就不通用啊
16F:→ uranusjr:Python 官方文件有说 Python 3 可以用旧一点的 protocol 09/26 14:36
17F:→ uranusjr:来 pickle 就会相容了啊... 09/26 14:36
虽然官方文件那样写,但实际上并没那麽美好
像是 datetime.datetime 这种内建物件就不相容
上面举例的 u'\ud800\udc00' 这种不合法字串也不相容
我问这个问题就是要用在自己写的 pickle 里面的 XD
18F:→ uranusjr:原来如此, 这样我真的没招了 orz 09/26 18:04
19F:→ s860134:用json.dumps和json.loads 能符合要求吗?? 09/27 19:16
很遗憾,还是不行耶...
20F:→ s860134:我还是不太懂 因为实际上我把 s=='\ud800\udc00' 是TRUE 09/28 09:09
在 python2 跟 python3 底下,这本来就都没问题呀
>>> s = u'\ud800\udc00'
>>> s == u'\ud800\udc00'
True
21F:→ s860134:而且我在Python3上 他不准我用 u'\ud800\udc00' 09/28 09:10
不准是指?如果是指不能 encode,那是因为某些编码(如 utf-8)有档 surrogates
※ 编辑: os653 来自: 114.46.115.224 (09/28 19:15)
22F:→ uranusjr:Python 3.3 之前的 Python 3 版本无法使用 u'' literal 09/28 20:39
23F:→ uranusjr:他应该是在说这个 (见 PEP 414) 09/28 20:39