写点什么

Python unicode 三明治

  • 2022 年 5 月 18 日
  • 本文字数:1146 字

    阅读完需:约 4 分钟

Python unicode三明治

大家在使用 python 读取文件或者处理 http 请求结果时,应该经常会遇到,特别是文件中有某些特殊字符,比如非英语的其他语种或者特殊数学符号等:


  • UnicodeDecodeError 报错

  • 以 b 开头的字符,类似b'caf\xc3\xa9'


这里就涉及到 python 中对字符的表示,python3 中对字符的表示分为 str 和 bytes(就是 b 开头的)。str 可以认为是人类可读的文本,bytes 字节码就是计算机能识别字节码(0/1)。


而 str 文本如何映射到计算机能识别的字节码?最早的 ASCII 编码格式将常用的英文字符表示成一系列数据码点,比如 a 用 97 表示,二进制为 0110001。但是 ASCII 使用的码点智能表示 0 到 127 的码点,其他的特殊无法表示,比如中文或者法语等。


这时 unicode 标准就逐渐完善来解决不同类型的字符表达,比如用 16bits(2 个字节)来表示汉字。一个 unicode 码点由一个 U+前缀加上 4,5,或 6 个 16 进制数字构成。在 python3 中,str 存储的是 unicode 字符,但是在网络 IO 中都是以字节形式进行传输的,所以 Unicode 标准定义了一系列编码标准用来将 unicode 编码为 bytes 用以计算机的存储和传输。这些 unicode 编码就是我们熟悉的 utf-8,gb2312 等编码格式。



text = 'café'print(type(text), text)# <class 'str'> café
encode_txt_utf8 = text.encode(encoding='utf8')print(type(encode_txt_utf8), encode_txt_utf8)# <class 'bytes'> b'caf\xc3\xa9'
encode_txt = text.encode(encoding='utf16')print(type(encode_txt), encode_txt, encode_txt.decode(encoding='utf16'))# <class 'bytes'> b'\xff\xfec\x00a\x00f\x00\xe9\x00' café
encode_txt.decode(encoding='utf8')# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
encode_txt_ascii = text.encode(encoding='ascii')print(type(encode_txt_ascii), encode_txt_ascii)# UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 3: ordinal not in range(128)
复制代码


从上面的代码可知:


  • 同一个字符,不同的编码格式编码出来的码点是不一样(如 utf8 和 utf16),é在 utf8 和 utf16 编码不一样

  • 而不同的编码能力范围是有限制,比如 ascii 是编码不了é;

  • 同时编码和解码的格式要一致才能正确解码


这里值得一提的是,python 进行业务处理的时候,Ned Batchelder 在 PyCon2012 上的讲座建议,在进行业务逻辑时,处理的都是可视的文本字符,即 unicode 三明治,也就是进入和输出业务要做好转换,中间的格式保持不变,避免不必要的错误。(图片来自网络,如有侵权联系删除)



另外,有一个问题就是在进行编码 encode 之后,在 decode 为可读文本时,必须知道 encode 的编码格式,两者必须一致才能正确解码,否则就会出现某些字符无法正确解码UnicodeDecodeError,更遗憾的是,你无法通过查看字节码来判断是哪一种编码,只能猜测。





发布于: 刚刚阅读数: 2
用户头像

公众号:人工智能微客(weker) 2019.11.21 加入

人工智能微客(weker)长期跟踪和分享人工智能前沿技术、应用、领域知识,不定期的发布相关产品和应用,欢迎关注和转发

评论

发布
暂无评论
Python unicode三明治_Python_AIWeker-人工智能微客_InfoQ写作社区