杰瑞科技汇

Python如何转换成Unicode?

Unicode vs. 编码

必须明确两个关键概念:

Python如何转换成Unicode?-图1
(图片来源网络,侵删)
  1. Unicode:它是一个字符集,而不是一种编码,你可以把它想象成一个巨大的字典,为世界上几乎所有的每一个字符(A, , , )都分配了一个唯一的数字,这个数字被称为码点,字符 A 的码点是 U+0041,字符 的码点是 U+4E2D,Unicode 只负责“是什么字符”,不关心“如何存储”。

  2. 编码:它是一套规则,规定了如何将 Unicode 码点转换成计算机可以存储和传输的字节序列,常见的编码有:

    • UTF-8:目前最流行、最通用的编码,它是一种可变长编码,英文字符(如 A)占用 1 个字节,而中文字符通常占用 3 个字节,UTF-8 是 ASCII 的超集,兼容 ASCII。
    • UTF-16:可变长编码,英文字符通常占用 2 个字节,中文字符通常也占用 2 或 4 个字节。
    • GBK / GB2312:主要用于简体中文的编码,不是 Unicode 标准。

一句话总结:Unicode 是“字符身份证号”,编码是“如何把身份证号存在计算机里”。


Python 2 vs. Python 3 的关键区别

理解 Python 2 和 Python 3 在处理 Unicode 上的巨大差异至关重要。

Python如何转换成Unicode?-图2
(图片来源网络,侵删)

Python 3 的处理方式(推荐,现代标准)

在 Python 3 中,字符串的默认类型就是 Unicode 字符串,你写的字符串字面量,Python 会自动将其处理为 Unicode。

str 类型就是 Unicode 字符串。

  • str: 表示 Unicode 字符串(内存中的抽象形式)。
  • bytes: 表示字节序列(磁盘上或网络中传输的实际数据)。

转换的核心是 encode()decode() 方法:

  • str.encode(encoding): 将 Unicode 字符串编码成字节序列。
  • bytes.decode(encoding): 将字节序列解码成 Unicode 字符串。

Python 3 中的具体操作和示例

从 Unicode 字符串得到字节序列 (编码)

当你需要将字符串写入文件、发送到网络或进行其他底层操作时,需要将其编码为字节。

Python如何转换成Unicode?-图3
(图片来源网络,侵删)
# 创建一个 Unicode 字符串
# 在 Python 3 中,'你好' 默认就是 str (Unicode) 类型
s_unicode = "你好,世界!"
print(f"原始字符串类型: {type(s_unicode)}")
print(f"原始字符串内容: {s_unicode}")
# --- 编码成不同的格式 ---
# 1. 编码成 UTF-8 字节序列
# 这是推荐的做法
s_utf8_bytes = s_unicode.encode('utf-8')
print(f"\n编码为 UTF-8 后的类型: {type(s_utf8_bytes)}")
print(f"编码为 UTF-8 后的内容: {s_utf8_bytes}")
# 输出: b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81'
# 每个字节都以 \x 开头
# 2. 编码成 UTF-16 字节序列
s_utf16_bytes = s_unicode.encode('utf-16')
print(f"\n编码为 UTF-16 后的类型: {type(s_utf16_bytes)}")
print(f"编码为 UTF-16 后的内容: {s_utf16_bytes}")
# 输出: b'\xff\xfe=\xe4\x8b\xbd\xbb\xbf,\x20\x16\xc7\x8d\x81\xef'
# 注意开头有 BOM (Byte Order Mark) \xff\xfe
# 3. 编码为 GBK (针对中文的特定编码)
s_gbk_bytes = s_unicode.encode('gbk')
print(f"\n编码为 GBK 后的类型: {type(s_gbk_bytes)}")
print(f"编码为 GBK 后的内容: {s_gbk_bytes}")
# 输出: b'\xc4\xe3\xba\xc3\xa1\xa3\xac\xca\xa1\xca\xa0\xxb9\xe3\x81'

从字节序列得到 Unicode 字符串 (解码)

当你从文件或网络读取数据时,得到的是字节序列,需要将其解码成 Unicode 字符串才能进行文本处理。

# 假设我们有一个从文件或网络读取的 UTF-8 编码的字节序列
bytes_from_file = b'\xe4\xbd\xa0\xe5\xa5\xbd' # 这是 "你好" 的 UTF-8 编码
# --- 解码成 Unicode 字符串 ---
# 1. 使用 UTF-8 解码
# 这必须和编码时使用的格式一致!
s_unicode_decoded = bytes_from_file.decode('utf-8')
print(f"解码后的类型: {type(s_unicode_decoded)}")
print(f"解码后的内容: {s_unicode_decoded}")
# 输出: 你好
# 2. 错误示范:用错误的编码解码
# 如果编码和解码的格式不一致,会抛出异常
try:
    s_unicode_decoded_wrong = bytes_from_file.decode('gbk')
except UnicodeDecodeError as e:
    print(f"\n使用错误的编码解码时出错: {e}")
    # 输出: 使用错误的编码解码时出错: 'gbk' codec can't decode byte 0xe4 in position 0: illegal multibyte sequence

处理 Python 2 的遗留数据

有时你可能会遇到 Python 2 生成的文件或数据,str 类型是字节串,而 unicode 类型才是真正的 Unicode 字符串。

  • str (Python 2): 字节串,等同于 Python 3 的 bytes
  • unicode (Python 2): Unicode 字符串,等同于 Python 3 的 str

在 Python 3 中处理这类数据,你需要先解码它:

# 假设这是从 Python 2 程序或一个旧文件中读取的 'str' (字节串)
py2_str = "你好"
# 在 Python 3 中,它的类型是 bytes
print(f"Python 2 风格的 'str' 在 Python 3 中的类型: {type(py2_str)}")
# 输出: <class 'bytes'>
# 你需要先知道它当初是用什么编码的,然后进行解码
# Python 2 的代码文件默认是 ASCII,但处理中文时常用 UTF-8
py2_unicode_str = py2_str.decode('utf-8') # 或者 'latin-1' 等等
print(f"解码后的类型: {type(py2_unicode_str)}")
print(f"解码后的内容: {py2_unicode_str}")
# 输出: 你好

最佳实践和总结

  1. 永远使用 Python 3,它在处理 Unicode 方面设计得更清晰、更安全。

  2. 在程序内部,始终使用 str (Unicode) 类型 进行所有文本操作(字符串拼接、分割、查找等),不要在内存中混用 strbytes

  3. 只在需要和外部世界交互时才进行编码/解码

    • 写入文件my_string.encode('utf-8')
    • 从文件读取file.read().decode('utf-8')
    • 发送网络请求my_string.encode('utf-8')
    • 接收网络响应response.read().decode('utf-8')
  4. 统一使用 UTF-8 作为你的标准编码,除非你有特殊的历史遗留系统或硬件限制,否则 UTF-8 是最佳选择。

  5. 处理编码错误:如果无法保证数据编码的 100% 准确性,可以在 encodedecode 时指定错误处理方式,而不是直接崩溃。

    • errors='ignore': 忽略无法编码/解码的字符。
    • errors='replace': 用占位符(如 )替换无法编码/解码的字符。
    • errors='strict': 遇到错误时抛出异常(默认行为)。
    # 示例:替换无法解码的字节
    bad_bytes = b'\xe4\xa0\xa0\xe4\xa0' # '好' 的 UTF-8 编码,但最后一个字节不完整
    s = bad_bytes.decode('utf-8', errors='replace')
    print(s)
    # 输出: 好�

希望这个详细的解释能帮助你彻底理解 Python 中的 Unicode 问题!

分享:
扫描分享到社交APP
上一篇
下一篇