Python 中的字符编码

PythonPythonBeginner
立即练习

引言

在本实验中,你将全面了解 Python 中的字符编码。我们将从探索字符编码的历史和基本概念开始,从 ASCII 和特定国家/地区的 ANSI 编码等早期编码的局限性,到 Unicode 标准及其各种实现(如 UTF-8)的发展和重要性。你将学习如何检查 Python 环境中的默认编码。

在此基础上,你将学习在 Python 中处理字符编码的实用技术。这包括使用 ord()chr() 函数在字符及其整数表示之间进行转换,以及掌握 encode()decode() 方法在字符串和字节之间进行转换。最后,你将学习如何有效地处理解码过程中可能出现的潜在编码错误,确保你的 Python 应用程序能够进行健壮且可靠的文本处理。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 88%。获得了学习者 98% 的好评率。

探索字符编码的历史和概念

在本步骤中,我们将探索字符编码的历史和基本概念。理解计算机如何表示文本对于处理各种数据格式和语言至关重要。

最初,计算机在美国开发,因此创建了 ASCII 编码。ASCII 使用一个字节来表示字符,包含英文字母、数字和符号,共 128 个字符。

随着计算机在全球范围内的普及,ASCII 证明不足以表示其他语言的字符。这导致了各种特定国家/地区的编码的开发,例如 GB2312、GBK、Big5 和 Shift_JIS。这些通常被统称为 ANSI 编码。

为了解决这些不同编码的局限性,Unicode 标准应运而生。Unicode 旨在为每种语言的每个字符提供唯一的二进制代码,从而实现跨不同平台和语言的一致文本处理。Unicode 定义了字符代码,但没有定义它们如何存储。

有几种编码方案实现了 Unicode,包括 UCS4、UTF-8、UTF-16 和 UTF-32。其中,UTF-8 因其与 ASCII 的向后兼容性而被广泛使用。

在 Python 3 中,默认编码是 UTF-8,这允许直接使用各种语言的字符,包括带重音的字符和符号。在 Python 2 等旧版本中,你通常需要在脚本开头使用类似 ## -*- coding: UTF-8 -*-## coding=utf-8 的注释来指定编码。

你可以使用 sys 模块检查 Python 环境中的默认编码。

首先,通过点击 Terminal -> New Terminal 打开 WebIDE 中的集成终端。

然后,通过输入 python 并按 Enter 键启动 Python 交互式解释器。

python

你应该会看到类似以下的输出:

Python 3.10.x (main, ...)
[GCC ...] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

现在,导入 sys 模块并检查默认编码:

import sys
sys.getdefaultencoding()

输出将显示默认编码,在 Python 3 中通常是 utf-8

>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
>>>

通过输入 exit() 并按 Enter 键退出 Python 解释器。

exit()

使用 ord() 和 chr() 转换字符和整数

在本步骤中,我们将学习如何使用 Python 内置函数 ord()chr() 在字符及其对应的 Unicode 整数表示之间进行转换。

在 Python 3 中,字符串使用 Unicode 表示。ord() 函数接收一个单独的字符作为输入,并返回其对应的 Unicode 十进制整数值。

让我们创建一个新的 Python 文件来试验这些函数。在 WebIDE 中,右键单击文件浏览器中的 project 目录,然后选择 New File。将文件命名为 char_conversion.py

在编辑器中打开 char_conversion.py 并添加以下代码:

## 使用 ord() 获取字符的 Unicode 十进制值
char1 = 'a'
char2 = 'é'
char3 = ';'

print(f"'{char1}' 的 Unicode 十进制值是:{ord(char1)}")
print(f"'{char2}' 的 Unicode 十进制值是:{ord(char2)}")
print(f"'{char3}' 的 Unicode 十进制值是:{ord(char3)}")

通过按 Ctrl + S(macOS 上为 Cmd + S)保存文件。

现在,再次打开集成终端(如果尚未打开),然后使用 python 命令运行脚本:

python char_conversion.py

你应该会看到类似以下的输出:

'a' 的 Unicode 十进制值是: 97
'é' 的 Unicode 十进制值是: 233
';' 的 Unicode 十进制值是: 59

chr() 函数执行相反的操作。它接收一个表示 Unicode 代码点的十进制整数(或十六进制整数),并返回相应的字符。

让我们向 char_conversion.py 添加更多代码来使用 chr() 函数。将以下行追加到现有代码中:

## 使用 chr() 从 Unicode 十进制值获取字符
int1 = 8364
int2 = 8482

print(f"Unicode 十进制值 {int1} 的字符是:{chr(int1)}")
print(f"Unicode 十进制值 {int2} 的字符是:{chr(int2)}")

## 你也可以将十六进制值与 chr() 一起使用
hex_int = 0x00A9 ## 字符 '©' 的十六进制表示
print(f"Unicode 十六进制值 {hex(hex_int)} 的字符是:{chr(hex_int)}")

再次保存文件。

从终端运行脚本:

python char_conversion.py

输出现在应该包含来自 chr() 函数的结果:

'a' 的 Unicode 十进制值是: 97
'é' 的 Unicode 十进制值是: 233
';' 的 Unicode 十进制值是: 59
Unicode 十进制值 8364 的字符是: €
Unicode 十进制值 8482 的字符是: ™
Unicode 十六进制值 0xa9 的字符是: ©

你可能想知道如何找到字符的十六进制 Unicode 表示。你可以使用 ord() 函数获取十进制值,然后使用内置的 hex() 函数将十进制值转换为其十六进制字符串表示。

将以下代码添加到 char_conversion.py

## 将字符转换为其十六进制 Unicode 表示
char_copyright = '©'
decimal_copyright = ord(char_copyright)
hexadecimal_copyright = hex(decimal_copyright)

print(f"'{char_copyright}' 的十六进制 Unicode 值是:{hexadecimal_copyright}")

保存文件并最后运行一次:

python char_conversion.py

最终输出将包括字符 '©' 的十六进制值:

'a' 的 Unicode 十进制值是: 97
'é' 的 Unicode 十进制值是: 233
';' 的 Unicode 十进制值是: 59
Unicode 十进制值 8364 的字符是: €
Unicode 十进制值 8482 的字符是: ™
Unicode 十六进制值 0xa9 的字符是: ©
'©' 的十六进制 Unicode 值是: 0xa9

这演示了如何将 ord()chr()hex() 一起用于在 Python 中处理字符编码。

使用 encode() 和 decode() 在字符串和字节之间进行转换

在本步骤中,我们将学习如何使用 encode()decode() 方法在 Python 字符串(Unicode)和 bytes 对象之间进行转换。这在处理需要以特定编码格式传输或存储的数据时至关重要。

encode() 方法用于使用指定的编码将字符串转换为 bytes 对象。它返回一个 bytes 对象。

让我们在 ~/project 目录中创建一个名为 encoding_decoding.py 的新 Python 文件。

在编辑器中打开 encoding_decoding.py 并添加以下代码:

## 定义一个字符串
my_string = 'café'

## 使用 UTF-8 编码字符串
encoded_utf8 = my_string.encode('utf-8')

## 使用 Latin-1 编码字符串
encoded_latin1 = my_string.encode('latin-1')

## 打印编码后的 bytes 对象
print(f"原始字符串:{my_string}")
print(f"UTF-8 编码:{encoded_utf8}")
print(f"Latin-1 编码:{encoded_latin1}")

保存文件。

现在,从集成终端运行脚本:

python encoding_decoding.py

你应该会看到显示原始字符串及其在 UTF-8 和 Latin-1 中的字节表示的输出:

原始字符串: café
UTF-8 编码: b'caf\xc3\xa9'
Latin-1 编码: b'caf\xe9'

请注意,bytes 对象的输出以 b' 开头,表示它们是 bytes 字面量。十六进制数字表示每个编码中字符串的字节序列。

decode() 方法用于使用指定的编码将 bytes 对象转换回字符串。

让我们向 encoding_decoding.py 添加代码以解码我们创建的 bytes 对象。将以下行追加到现有代码中:

## 将 bytes 对象解码回字符串
decoded_utf8 = encoded_utf8.decode('utf-8')
decoded_latin1 = encoded_latin1.decode('latin-1')

## 打印解码后的字符串
print(f"UTF-8 解码:{decoded_utf8}")
print(f"Latin-1 解码:{decoded_latin1}")

保存文件。

再次运行脚本:

python encoding_decoding.py

输出现在将显示成功从 UTF-8 和 Latin-1 bytes 解码的原始字符串:

原始字符串: café
UTF-8 编码: b'caf\xc3\xa9'
Latin-1 编码: b'caf\xe9'
UTF-8 解码: café
Latin-1 解码: café

这演示了使用特定编码将字符串编码为 bytes 以及将 bytes 解码回字符串的基本过程。为了避免错误,在编码和解码时使用正确的编码至关重要,我们将在下一步中探讨这一点。

处理解码过程中的编码错误

在本步骤中,我们将探讨当你尝试使用错误的编码解码字节时会发生什么,以及如何处理这些错误。

正如我们在上一步中看到的,成功解码字节需要知道创建这些字节的原始编码。如果你尝试使用不兼容的编码来解码字节,Python 将引发一个错误。

让我们修改 encoding_decoding.py 文件来演示这一点。在编辑器中打开文件,并在末尾添加以下代码:

## 尝试使用 ASCII 解码 Latin-1 编码的字节
try:
    decoded_incorrectly = encoded_latin1.decode('ascii')
    print(f"使用 ASCII 解码 Latin-1: {decoded_incorrectly}")
except UnicodeDecodeError as e:
    print(f"使用 ASCII 解码 Latin-1 时出错:{e}")

保存文件。

从终端运行脚本:

python encoding_decoding.py

输出现在将包含尝试使用 ASCII 解码 Latin-1 字节时的错误消息:

原始字符串: café
UTF-8 编码: b'caf\xc3\xa9'
Latin-1 编码: b'caf\xe9'
UTF-8 解码: café
Latin-1 解码: café
使用 ASCII 解码 Latin-1 时出错: 'ascii' codec can't decode byte 0xe9 in position 3: ordinal not in range(128)

UnicodeDecodeError 表明 ASCII 编码器遇到了根据 ASCII 标准无效的字节。在这种情况下,字节 0xe9 是 'é' 的 Latin-1 表示,但它不是有效的 ASCII 字符(ASCII 只包含 0-127 的字符)。

解码时,你还可以使用 decode() 方法的 errors 参数来指定如何处理错误。常见的错误处理策略包括:

  • 'strict'(默认):引发 UnicodeDecodeError
  • 'ignore':忽略无法解码的字节。
  • 'replace':用替换字符(通常是 ``)替换无法解码的字节。
  • 'xmlcharrefreplace':用 XML 字符引用替换无法解码的字节。

让我们向 encoding_decoding.py 添加使用 'ignore''replace' 错误处理策略的示例。追加以下代码:

## 尝试使用 ASCII 和错误处理来解码 Latin-1 编码的字节
decoded_ignore = encoded_latin1.decode('ascii', errors='ignore')
decoded_replace = encoded_latin1.decode('ascii', errors='replace')

print(f"使用 ASCII 解码 Latin-1 (忽略错误): {decoded_ignore}")
print(f"使用 ASCII 解码 Latin-1 (替换错误): {decoded_replace}")

保存文件。

再次运行脚本:

python encoding_decoding.py

输出现在将显示带有错误处理的结果:

原始字符串: café
UTF-8 编码: b'caf\xc3\xa9'
Latin-1 编码: b'caf\xe9'
UTF-8 解码: café
Latin-1 解码: café
使用 ASCII 解码 Latin-1 时出错: 'ascii' codec can't decode byte 0xe9 in position 3: ordinal not in range(128)
使用 ASCII 解码 Latin-1 (忽略错误): caf
使用 ASCII 解码 Latin-1 (替换错误): caf

如你所见,'ignore' 的结果是 "caf",因为无效字节被忽略了,移除了 'é' 字符。'replace' 用替换字符 `` 替换了无效字节,结果是 "caf"。

选择合适的错误处理策略取决于你的具体需求。在大多数情况下,最好在开发过程中使用 'strict' 来及早捕获编码问题。在生产环境中,如果你需要处理可能存在编码问题的数据,可以选择 'replace''ignore',但请注意这可能导致数据丢失或损坏。

总结

在本实验中,我们探讨了字符编码的历史和基本概念,从 ASCII 及其局限性开始,这导致了各种国家特定编码的开发,并最终发展到 Unicode 标准。我们了解到 Unicode 为每个字符提供了唯一的代码,并通过 UTF-8 等各种编码方案实现,UTF-8 是 Python 3 的默认编码,并且与 ASCII 向后兼容。我们还学习了如何使用 sys 模块检查 Python 中的默认编码。

然后,我们练习了使用 ord()chr() 函数在字符及其整数表示之间进行转换,以及使用 encode()decode() 方法在字符串和字节之间进行转换。最后,我们解决了如何在解码过程中处理可能发生的编码错误。

Morty Proxy This is a proxified and sanitized view of the page, visit original site.