做了一个 python 2 & 3 处理字符串的流程图

2016-06-10 16:55:51 +08:00
 panyanyany

这是我在阅读一些资料后总结出来的,不知道我理解得对不对

5115 次点击
所在节点    Python
6 条回复
justou
2016-06-10 17:59:17 +08:00
一直用 py2 处理各种编码, 看了 5 分钟这个流程图, 最后还是没明白是啥意思
fy
2016-06-10 18:56:30 +08:00
楼主这个图太迷了,但大体差不多是这意思。

关于读取代码时的编码:
指定的 coding 最大,除此之外, py2 以系统编码为默认编码, py3 则是 utf8

关于字节串、字符串在内存中储存:
py3 的字节串(bytes)与 py2 的 str 行为一致,直接将串读入内存
py3 的字符串( str )与 py2 的 unicode 行为一致,将串转为 latin1/ucs2/ucs4 编码后储存
itlynn
2016-06-10 19:09:03 +08:00
在 Linux 用 Python2.7 ,终端默认就是 utf-8 ,没遇到编码的问题,杜绝 windows …
justou
2016-06-10 21:51:30 +08:00
也写个简单总结吧

unicode 字符集说白了就是 0 到 0x10ffff 这一串数字(0 到 1114111),也叫码点, 比如汉字"中", python 中的 unicode 表示为 u'\u4e2d', \u 是转义字符, 码点是 0x4e2d(十进制为 20013). 这些数字需要转化成字节序列(0-255)在内存中表示时, 就要有一个规则将 unicode 码点(比如 0x4e2d)转换为字节序列, 这个规则就是编码, 这个过程反过来时的规则叫做解码, 另外只有 UTF 家族(UTF-8, UTF-16,...)的编码器才能将任意 unicode 码点完全正确的编码为字节序列.

python 处理各种编码的一个准则: early decode, always unicode, late encode.

early decode:
在获取外部输入时(文件, 终端, 网络...)尽早的将其解码为 unicode. 如果已知外部输入的编码时, 就用那个编码将输入 decode 就是; 如果不知道的话就只能靠统计的方法检测其编码了, 没有其它完全可靠的算法(但是 utf 编码的可以直接检测 BOM), 比如大多数浏览器自动检测编码就是靠统计, 最后以某个大概率统计出具体编码, python 的一个扩展库 chardet 也是基于统计, 如果是写爬虫的话, chardet 几乎是一个必须的库吧(requests 都直接把 chardet 放在自己的包里面了), 如果是读取本地文件, py2 要依赖标准库的 codecs 解码, py3 的 open 函数自带解码参数

always unicode:
程序内部处理过程中都统一为 unicode

late encode:
程序处理完, 需要将其输出了, 无论输出在终端是还是在文件, 都是给人看的, 需要将 unicode 码点转换为字节序列, 比如说简中 windows 的控制台吧, 默认代码页是 cp932, 编码数大概是 23,940 个(跟 unicode 的 1114112 个比较下就知道为啥好多字符都不能显示在控制台了), 显示在控制台一般能起个简单观测的作用, 可以简单的 ignore 掉不能显示的字符
eg:
---------------------------------------------------------------------------------------------------------------------------------------------
# -*- encoding = utf-8 -*-
# 上面这一行的作用是提示 python 虚拟机, 它将要读取的这个代码文件是 utf-8 编码的.因为这里面会有英语以外的字符
# 这不是强制的, 如果虚拟机发现不是 utf-8 编码的, 会用默认的 ascii 读取该代码文件, 于是有不是英文的字符就会报错
# 当然你也必须保存为 utf-8, 而且是有 BOM(Byte Order Mark)的 utf-8 文件, 试试用其它编辑器改成 No BOM 或者
# 其它编码, 虚拟机检测不到文件的 BOM, 也转为使用 ascii 解码并读取该文件
import locale
local_encoding = locale.getpreferredencoding() # 获取控制台默认编码, 不一定是 cp932 呀
print local_encoding

alice = u"アリス・マーガトロイド"
# 这个日文的点・在 cp936 的控制台是显示不出来的, 如果想在控制台显示这个字符串,
# 可以在编码时选择 ignore 不能编码的字符,或者 replace(默认使用?替换)
try:
print alice
except Exception as e:
print e
print alice.encode(local_encoding, errors="ignore")
---------------------------------------------------------------------------------------------------------------------------------------------

用 windows 终端运行看看吧, 当然在 IDE 中 print alice 可能能完整显示, 因为输出被重定向了
------------------------------------------
在 python 自带的 IDLE 中运行的结果:
cp936
アリス・マーガトロイド
アリスマーガトロイド
IDLE 中输出被重定向, 点正确显示
使用 cp936 编码后点被 ignore 了
----------------------------------------
控制台运行的结果:
cp936
'gbk' codec can't encode character u'\u30fb' in position 3: illegal multibyte sequence
アリスマーガトロイド
编码失败
忽略不能编码的码点

输出到文件跟输出到控制台是一样的, 都是需要某个具体编码的地方, 当然这时可以指定能完全编码 unicode 的 UTF 系列编码器完全无误的记录下来.

文本的编码解码可以类比音视频的编码解码, 比如用一个音乐播放器播放视频, 解码器给错, 当然不能播放,decode error; 压制视频的时候, 给 video 指定一个 audio 的编码器, encode error
hanbaobao2005
2016-06-12 13:01:27 +08:00
python2 转换 unicode 分支的条件是什么啊?能在流程图标注一下么?谢谢
panyanyany
2016-06-14 07:38:58 +08:00
@hanbaobao2005 呃,没有条件,图中的分支其实是表示 “当遇到 s = u"中文" 时,会这样处理……”

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/284787

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX