DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

以下部分参考[1],这里复制了其中一部分是为了防止原文被移动或删除。


概述

Python 中有字符串类型(str)和字节类型(byte),以及 Python 编码中最常见也是最顽固的两个错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: invalid continuation byte

这一期就从这两个错误入手,分析 Python 中 Unicode 的正确用法。这篇短文并不能保证你可以永远杜绝上面两个错误,但是希望在下次遇到这个错误的时候知道错在哪里、应该从哪里入手。

编码与解码

上面的两个错误分别是 UnicodeEncodeError 和 UnicodeDecodeError,也就是说分别在 Unicode 编码(Encode)和解码(Decode)过程中出现了错误,那么编码和解码究竟分别意味着什么?根据维基百科字符编码的定义:

字符编码(英语:Character encoding)、字集码是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。

简单来说就是把人类通用的语言符号翻译成计算机通用的对象,而反向的翻译过程自然就是解码了。Python 中的字符串类型代表人类通用的语言符号,因此字符串类型有encode()方法;而字节类型代表计算机通用的对象(二进制数据),因此字节类型有decode()方法。

print("??".encode())
b'\xf0\x9f\x8c\x8e\xf0\x9f\x8c\x8f'
print(b'\xf0\x9f\x8c\x8e\xf0\x9f\x8c\x8f'.decode())
??

 

既然说编码和解码都是翻译的过程,那么就需要一本字典将人类和计算机的语言一一对应起来,这本字典的名字叫做字符集,从最早的 ASCII 到现在最通用的 Unicode,它们的本质是一样的,只是两本字典的厚度不同而已。ASCII 只包含了26个基本拉丁字母、阿拉伯数目字和英式标点符号一共128个字符,因此只需要(不占满)一个字节就可以存储,而 Unicode 则涵盖的数据除了视觉上的字形、编码方法、标准的字符编码外,还包含了字符特性,如大小写字母,共可包含 1.1M 个字符,而到现在只填充了其中的 110K 个位置。

字符集中字符所存储的位置(或者说对应的计算机通用的数字)称之为码位(code point),例如在 ASCII 中字符 ‘$’ 的码位就是:

print(ord('$'))
36

ASCII 只需要一个字节就能存下所有码位,而 Unicode 则需要几个字节才能容纳,但是对于具体采用什么样的方案来实现 Unicode 的这种映射关系,也有很多不同的方案(或规则),例如最常见(也是 Python 中默认的)UTF-8,还有 UTF-16、UTF-32 等,对于它们规则上的不同这里就不深入展开了。当然,在 ASCII 与 Unicode 之间还有很多其他的字符集与编码方案,例如中文编码的 GB2312、繁体字的 Big5 等等,这并不影响我们对编码与解码过程的理解。


以上全部参考[1],下面是我根据[1]整理出来的最终应用代码。


def try_encode(s, encoding="utf-8"):
    if s is None:
        print('[tryEncode]: input param None!')
        return s
    try:
        return s.encode(encoding)
    except UnicodeEncodeError as err:
        print(err)


def try_decode(s, decoding="utf-8"):
    try:
        return s.decode(decoding)
    except UnicodeDecodeError as err:
        print(err)


def str_decode(string):
    while True:
        dec = try_decode(string, "utf-8")
        if dec is not None:
            break
        dec = try_decode(string, "ascii")
        if dec is not None:
            break
        dec = try_decode(string, "GB2312")
        if dec is not None:
            break
        dec = try_decode(string, "GBK")
        if dec is not None:
            break
        dec = try_decode(string, "Big5")
        if dec is not None:
            break
        print('[str_decode]: unknown encoding')
        dec = None
        break

    return dec

参考文献

[1] PyTips 0x09 - Python 中 Unicode 的正确用法
[2] python 之路,致那些年,我们依然没搞明白的编码

 
posted on   DoubleLi  阅读(552)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2019-01-30 双网卡单IP实现网卡冗余与负载均衡
2018-01-30 live555源码分析----RSTPServer创建过程分析
点击右上角即可分享
微信分享提示