杰瑞科技汇

Python中unicode类型如何正确使用?

这是一个非常重要且基础的概念,尤其是在处理文本数据时,理解它可以帮助你避免很多常见的编码错误(UnicodeDecodeErrorUnicodeEncodeError)。

Python中unicode类型如何正确使用?-图1
(图片来源网络,侵删)

核心概念:从 strbytes

在 Python 3 中,处理文本和二进制数据的方式非常清晰,这与 Python 2 有根本性的不同,关键在于理解两个核心类型:

  1. str (字符串类型): 这是文本的抽象表示,在 Python 3 中,str 类型就是Unicode 字符串,它内部存储的是字符的码点(code points),而不是具体的字节序列,你可以把它想象成一个人类可读的字符集合。

  2. bytes (字节类型): 这是二进制数据的原始序列,它是一个由 0 到 255 之间的整数组成的序列,计算机底层存储和传输的都是 bytes 类型。

最重要的关系是: str 是文本的抽象,而 bytes 是文本在计算机中存储和传输的具体形式,要将 str 转换为 bytes,你需要进行编码;反之,将 bytes 转换为 str,则需要解码

Python中unicode类型如何正确使用?-图2
(图片来源网络,侵删)

str 类型:Unicode 字符串

在 Python 3 中,当你写 '你好'"Hello" 时,你创建的就是一个 str 对象,它本质上是 Unicode。

# 这是一个 str 类型,是 Unicode 字符串
s = "你好,世界!Hello, World!"
# 查看它的类型
print(type(s))  # <class 'str'>
# 查看它的长度(字符个数)
print(len(s))  # 14
# 你可以直接索引 Unicode 字符
print(s[0])     # 你
print(s[7])     # H

Unicode 字符的表示

Python 提供了多种方式在字符串中表示 Unicode 字符:

  1. 直接使用: 直接输入字符即可,前提是你的源代码文件编码是 UTF-8(这是现代 Python 的默认设置)。

    s = "café"
  2. 转义序列: 使用 \u 后跟 4 位十六进制数表示一个 Unicode 码点。

    Python中unicode类型如何正确使用?-图3
    (图片来源网络,侵删)
    # \u00e9 是 'é' 的 Unicode 码点
    s = "caf\u00e9"
    print(s)  # 输出: café
  3. 十六进制转义: 使用 \U 后跟 8 位十六进制数(可以表示更大的码点)。

    # \U0001F600 是 '😀' 的 Unicode 码点
    s = "Hello\U0001F600"
    print(s)  # 输出: Hello😀
  4. 名称转义: 使用 \N{字符名称}

    # \N{LATIN SMALL LETTER E WITH ACUTE} 也是 'é'
    s = "caf\N{LATIN SMALL LETTER E WITH ACUTE}"
    print(s)  # 输出: café

编码与解码:连接 strbytes 的桥梁

这是处理文本数据最关键的一步。

编码

str 转换为 bytes 的过程。

语法: str.encode(encoding='utf-8', errors='strict')

  • encoding: 指定使用的编码规则,如 'utf-8', 'gbk', 'ascii', 'latin-1' 等。
  • errors: 指定如何处理编码错误,如 'strict' (默认,抛出异常), 'ignore' (忽略), 'replace' (替换为 ) 等。
# 定义一个 Unicode 字符串
text_str = "你好,世界!"
# 1. 使用 UTF-8 编码 (最常用)
# UTF-8 是一种可变长度的编码,英文字符占1字节,中文字符通常占3字节
utf8_bytes = text_str.encode('utf-8')
print(f"UTF-8 编码结果: {utf8_bytes}")
print(f"类型: {type(utf8_bytes)}")
print(f"字节长度: {len(utf8_bytes)}") # 每个中文字符3个字节,共6个中文字符,18字节
# 输出:
# UTF-8 编码结果: b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81'
# 类型: <class 'bytes'>
# 字节长度: 18
# 2. 使用 GBK 编码 (常用于简体中文环境)
# GBK 也是一种中文编码,中文字符通常占2字节
gbk_bytes = text_str.encode('gbk')
print(f"\nGBK 编码结果: {gbk_bytes}")
print(f"字节长度: {len(gbk_bytes)}") # 6个中文字符,共12字节
# 输出:
# GBK 编码结果: b'\xc4\xe3\xba\xc3\xca\xa1\xca\xa0\xcd\xa8\xa1\xa3'
# 字节长度: 12
# 3. 尝试用 ASCII 编码 (会失败,因为 ASCII 不支持中文字符)
try:
    ascii_bytes = text_str.encode('ascii')
except UnicodeEncodeError as e:
    print(f"\n用 ASCII 编码失败: {e}")

解码

bytes 转换为 str 的过程。编码和解码必须使用相同的编码规则,否则会出现乱码。

语法: bytes.decode(encoding='utf-8', errors='strict')

# 假设我们从网络或文件中收到了一段 UTF-8 编码的字节流
received_bytes = b'\xe4\xbd\xa0\xe5\xa5\xbd' # 这是 "你好" 的 UTF-8 编码
# 1. 使用正确的编码 (UTF-8) 解码
decoded_str_utf8 = received_bytes.decode('utf-8')
print(f"用 UTF-8 解码: {decoded_str_utf8}")
# 输出: 用 UTF-8 解码: 你好
# 2. 使用错误的编码 (GBK) 解码 (会产生乱码)
# 因为 GBK 会尝试用不同的字节组合来解释这些字节
decoded_str_gbk = received_bytes.decode('gbk')
print(f"用 GBK 解码 (乱码): {decoded_str_gbk}")
# 输出: 用 GBK 解码 (乱码): 浣犲ソ

常见错误及处理

错误 1: UnicodeDecodeError

原因: 尝试用错误的编码去解码 bytes 数据。 场景: 读取一个文件,假设文件是 UTF-8 编码,但你错误地用 latin-1 去读。

# 一个 UTF-8 编码的字节流
utf8_data = b'caf\xc3\xa9' # 这是 "café" 的 UTF-8 编码
# 错误示范:用 latin-1 解码
# latin-1 会把每个字节直接映射到一个字符,\xc3 和 \xa9 会被当作两个独立的字符
try:
    wrong_decode = utf8_data.decode('latin-1')
    print(f"错误解码结果: {wrong_decode}") # 输出: café
except UnicodeDecodeError:
    print("解码失败!")
# 正确示范:用 UTF-8 解码
correct_decode = utf8_data.decode('utf-8')
print(f"正确解码结果: {correct_decode}") # 输出: café

错误 2: UnicodeEncodeError

原因: 尝试将一个 str 编码成一种它不支持的编码。 场景: 尝试将中文字符串编码成 ascii

chinese_str = "你好"
# 错误示范:尝试编码成 ASCII
# ASCII 编码表只包含英文字母、数字和符号,不包含中文字符
try:
    chinese_str.encode('ascii')
except UnicodeEncodeError as e:
    print(f"编码失败: {e}")
    # 输出: 编码失败: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
# 解决方案1:忽略无法编码的字符
encoded_ignore = chinese_str.encode('ascii', errors='ignore')
print(f"忽略错误编码: {encoded_ignore}") # 输出: b''
# 解决方案2:用 ? 替换无法编码的字符
encoded_replace = chinese_str.encode('ascii', errors='replace')
print(f"替换错误编码: {encoded_replace}") # 输出: b'??'
# 解决方案3:使用更通用的编码,如 UTF-8
encoded_utf8 = chinese_str.encode('utf-8')
print(f"用 UTF-8 编码: {encoded_utf8}") # 输出: b'\xe4\xbd\xa0\xe5\xa5\xbd'

实践建议

  1. 坚持使用 UTF-8: 在你的整个应用程序中,统一使用 UTF-8 作为编码标准,从源代码文件保存、内部数据处理,到网络请求和文件读写,都尽量使用 UTF-8,这是避免绝大多数编码问题的最佳实践。

  2. 明确区分文本和二进制:

    • 当你的数据是人类可读的文本时,始终使用 str 类型。
    • 当你的数据是、网络数据包、图片、加密数据等原始字节流时,始终使用 bytes 类型。
  3. 尽早解码,尽可能晚编码:

    • 尽早解码: 当从外部(文件、网络、数据库)接收到 bytes 数据时,立即解码成 str 类型,然后在程序内部统一使用 str 进行所有逻辑处理。
    • 尽可能晚编码: 只有在需要将数据持久化到文件或通过网络发送时,才将 str 编码成 bytes
  4. 处理外部数据时要小心: 如果你无法控制外部数据的编码(比如一个旧系统传来的文件),你需要提前知道或猜测它的编码,可以使用 chardet 等第三方库来检测编码,但这并非 100% 可靠。

总结表格

特性 str (Python 3) bytes (Python 3)
类型 Unicode 字符串 二进制数据
用途 存储和处理文本 存储和传输原始数据(文件、网络包等)
创建方式 'text', "text" b'bytes', b"bytes"
转换关系 .encode() -> bytes .decode() -> str
索引 返回一个字符 (str) 返回一个字节 (int)
长度 字符个数 字节个数
典型操作 s.find(), s.split(), s.replace() b.find(), b.split(), b.replace() (操作基于字节)

掌握 strbytes 的区别以及它们之间的转换,是成为一名熟练的 Python 开发者的必经之路。

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