作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
Unicode 是世界上大多数计算机的标准字符编码,它确保文本(包括字母、符号、表情符号甚至控制符号)在不同设备、平台和数字文档中显示相同,无论使用的是哪种操作系统或软件。
Unicode本身不是编码,但更像是地球上几乎所有可能的字符的数据库。 Unicode 包含一个代码点,其数据库中的每个字符的标识符,可以有从 0 到 1.1 百万的值,这意味着它很不太可能在任何时候失去这些独特的代码点。 Unicode 中的每个代码点都被表示为U+n
,其中U+
意味着它是一个 Unicode 代码点,而n
是该字符的四到六个六位数的集合。
与此同时,对Python等编程语言提出了正确处理文本的要求,使软件能够实现国际化,Python可以用于各种各样的事情,从电子邮件到服务器到Web,并且具有优雅的处理Unicode的方式,它通过采用Unicode标准来处理其字符串。
但是,在Python中使用Unicode可以让人困惑并导致错误,本教程将提供如何在Python中使用Unicode的基本知识,以帮助您避免这些问题,您将使用Python来解释Unicode,使用Python的正常化函数来规范数据,并处理Python的Unicode错误。
前提条件
要遵循本教程,您将需要:
- Python 在本地或在远程服务器上安装. 如果您尚未安装 Python,您可以通过遵循我们的教程(How To Install Python 3 and Set Up a Programming Environment)(https://www.digitalocean.com/community/tutorial_collections/how-to-install-python-3-and-set-up-a-programming-environment)来完成此操作。选择适合您的 Linux 发行版的版本 *熟悉基本的 Python 编程和 Python 字符串方法 *了解如何使用 Python 互动控制台
步骤 1 — 将Unicode代码点转换为Python
编码是以计算机可读的形式表示数据的过程,有许多方法来编码数据(ASCII、拉丁文1和更多),每个编码都有其自身的优势和弱点,但也许最常见的是UTF-8。 这是一个允许世界各地的字符在单个字符集中表示的编码类型。 因此,UTF-8对于任何与国际化数据合作的人来说都是必不可少的工具。 总的来说,UTF-8对于大多数目的都是一个很好的选择。 它相对高效,可以与各种软件一起使用。 UTF-8采用了Unicode代码点,并将其转换成一个计算机可以理解的六十字节。 换句话说,Unicode是地图,而UTF-8允许计算机理解该地图。
在Python 3,默认的字符串编码是UTF-8,这意味着Python字符串中的任何Unicode代码点都会自动转换为相应的字符。
在此步骤中,您将使用其在Python中的Unicode代码点创建版权符号(©)。
1>>> s = '\u00A9'
2>>> s
在上一代代码中,你创建了一条有 Unicode 代码点 u00A9
的字符串. 如前所述,由于 Python 字符串默认使用 UTF-8 编码,打印的 `s 值会自动将其更改为相应的 Unicode 符号。
1[secondary_label Output]
2'©'
Python 编程语言为编码和解码字符串提供了内置的函数. encode()
函数将字符串转换为字节字符串。
要证明这一点,打开 Python 交互式控制台,输入以下代码:
1>>> '🅥'.encode('utf-8')
这会产生字符的字节字符串作为输出:
1[secondary_label Output]
2b'\xf0\x9f\x85\xa5'
请注意,每个字节都有一个\x
,这表明它是一个六十字节的数字。
<$>[注] 注: 在 Windows 和 Mac 上键入特殊的 Unicode 字符是不同的。在前面的代码中,以及本教程中使用符号的所有代码中,您可以使用 Windows 中的字符地图实用程序插入符号。
接下来,您将使用 decode()
函数将字节字符串转换成一个字符串. decode()
函数接受编码类型作为一个参数. 值得一提的是, decode()
函数只能解码字节字符串,该字符串的开头是使用字母 b
来指定。
在您的控制台中:
1>>> b'\xf0\x9f\x85\xa5'.decode('utf-8')
代码会像这样返回输出:
1[secondary_label Output]
2'🅥'
你现在对Python中的Unicode解释有了基本的理解,接下来,你将沉浸在Python内置的unicodedata
模块中,在你的字符串上执行先进的Unicode技术。
第2步:在Python中规范Unicode
在此步骤中,您将在Python中正常化Unicode。Normalization有助于确定用不同的字体写的两个字符是否相同,这在两个具有不同的代码点的字符产生相同结果时是有用的。
下面的代码示例进一步证明了这一点。
1>>> styled_R = 'ℜ'
2>>> normal_R = 'R'
3>>> styled_R == normal_R
你会得到以下的输出:
1[secondary_label Output]
2False
代码打印假
作为输出,因为Python字符串不认为两个字符是相同的。
在Unicode中,有些字符是通过将两个或多个字符合并成一个来创建的。在这种情况下,规范化很重要,因为它使您的字符串保持一致。
1>>> s1 = 'hôtel'
2>>> s2 = 'ho\u0302tel'
3>>> len(s1), len(s2)
在之前的代码中,您创建了一个包含ô
字符的字符串 s1,而在第二行中,字符串
s2’包含 circumflex 字符的代码点( ).执行后,代码返回以下输出:
1[secondary_label Output]
2(5, 6)
上面的输出显示,这两个字符串由相同的字符组成,但具有不同的长度,这意味着它们将失败平等。
1>>> s1 == s2
代码返回以下输出:
1[secondary_label Output]
2False
虽然字符串变量s1
和s2
产生相同的Unicode字符,但它们的长度不同,因此不等同。
您可以使用「normalize()」函数解决此问题,这是您在下一步所做的。
步骤 3 – 使用 NFD、NFC、NFKD 和 NFKC 规范 Unicode
在此步骤中,您将使用Python的 unicodedata库中的normalize()
函数将Unicode字符串正常化,该函数提供字符搜索和正常化功能。
NFD标准化表格将一个字符分解为多个组合字符,使文本不敏感,这在搜索和排序中很有用。
打开您的控制台并键入以下内容:
1>>> from unicodedata import normalize
2>>> s1 = 'hôtel'
3>>> s2 = 'ho\u0302tel'
4>>> s1_nfd = normalize('NFD', s1)
5>>> len(s1), len(s1_nfd)
代码产生以下输出:
1[secondary_label Output]
2(5, 6)
正如示例所示,正常化字符串s1
会使其长度增加一个字符,这是因为ô
符号被分为两个字符o
和 ̈
,您可以通过使用以下代码来确认:
1>>> s1.encode(), s1_nfd.encode()
结果显示,在编码正常化字符串后,字符o
与字符串s1_nfd
中的字符 ̈
分开:
1[secondary_label Output]
2(b'h\xc3\xb4tel', b'ho\xcc\x82tel')
NFC标准化表格首先分解一个字符,然后用任何可用的组合字符重新组合它.由于NFC构成一个字符串以产生最短的输出,W3C建议在网络上使用NFC。
例如,在您的互动控制台中输入以下内容:
1>>> from unicodedata import normalize
2>>> s2_nfc = normalize('NFC', s2)
3>>> len(s2), len(s2_nfc)
代码产生以下输出:
1[secondary_label Output]
2(6, 5)
在示例中,正常化字符串 s2
会使其长度减少一个,您可以通过在交互式控制台中运行以下代码来确认此情况:
1>>> s2.encode(), s2_nfc.encode()
代码的输出是:
1[secondary_label Output]
2(b'ho\xcc\x82tel', b'h\xc3\xb4tel')
输出显示o
和``字符合并为一个单一的ô
字符。
标准化形式 NFKD和 NFKC用于严格
的规范化,可用于与搜索和 Unicode 字符串中的模式匹配有关的各种问题。
NFD 和 NFC 规范化表格分解字符,但 NFKD 和 NFKC 对不相似但等同的字符执行兼容性分解,删除任何格式区别。
下面的示例显示了 NFD 和 NFKD 规范化表单之间的区别。
1>>> s1 = '2⁵ô'
2>>> from unicodedata import normalize
3>>> normalize('NFD', s1), normalize('NFKD', s1)
你会得到以下的输出:
1[secondary_label Output]
2('2⁵ô', '25ô')
输出显示,NFD表格无法在字符串s1
中分解表达符号,但NFKD切断了表达符号的格式化,并将兼容性字符(在这种情况下,表达符号5
)替换为其等价字符(5
作为一个数字)。
1>>> len(normalize('NFD', s1)), len(normalize('NFKD', s1))
代码将返回如下:
1[secondary_label Output]
2(4, 4)
NFKC 正常化表格以类似的方式工作,但它组成字符,而不是分解它们。
1>>> normalize('NFC', s1), normalize('NFKC', s1)
代码返回如下:
1[secondary_label Output]
2('2⁵ô', '25ô')
由于 NFKC 遵循构成方法,你应该期望 ô
字符的字符串被缩短为一个,而不是在分解的情况下被延长为一个。
1>>> len(normalize('NFC', s1)), len(normalize('NFKC', s1))
这将返回以下输出:
1[secondary_label Output]
2(3, 3)
通过执行前面的步骤,你将有工作知识的标准化形式的类型和它们之间的差异. 在下一步,你将解决Unicode错误在Python。
第4步:解决Python中的Unicode错误
在 Python 中处理 Unicode 时,可以出现两种类型的 Unicode 错误: UnicodeEncodeError 和 UnicodeDecodeError. 虽然这些 Unicode 错误可能令人困惑,但它们可以管理,您将在此步骤中修复这两个错误。
如何解决 UnicodeEncode错误
Unicode 编码是使用特定的编码将 Unicode 字符串转换为字节的过程,当尝试编码包含无法在指定的编码中表示的字符串时,会出现 UnicodeEncode Error。
要创建此错误,您将编码包含非 ASCII 字符集的一部分字符串。
打开您的控制台并键入以下内容:
1>>> ascii_supported = '\u0041'
2>>> ascii_supported.encode('ascii')
以下是你的输出:
1[secondary_label Output]
2b'A'
然后输入以下内容:
1>>> ascii_unsupported = '\ufb06'
2>>> ascii_unsupported.encode('utf-8')
你会得到以下的输出:
1[secondary_label Output]
2b'\xef\xac\x86'
最后,输入以下内容:
1>>> ascii_unsupported.encode('ascii')
但是,当您运行此代码时,您会收到以下错误:
1[secondary_label Output]
2Traceback (most recent call last):
3 File "<stdin>", line 1, in <module>
4UnicodeEncodeError: 'ascii' codec can't encode character '\ufb06' in position 0: ordinal not in range(128)
ASCII 具有有限的字符数,Python 当它在 ASCII 图集中找不到的字符时会丢失错误,因为 ASCII 图集无法识别代码点 \ufb06
,Python 会返回一个错误消息,称 ASCII 范围仅为 128 个,而该代码点的相应十进制等级不在该范围内。
您可以通过在encode()
函数中使用一个错误
参数来处理 UnicodeEncodeError。
打开您的控制台并键入以下内容:
1>>> ascii_unsupported = '\ufb06'
2>>> ascii_unsupported.encode('ascii', errors='ignore')
您将获得以下输出
1[secondary_label Output]
2b''
下一个类型如下:
1>>> >>> ascii_unsupported.encode('ascii', errors='replace')
产量将是:
1[secondary_label Output]
2b'?'
最后,输入以下内容:
1>>> ascii_unsupported.encode('ascii', errors='xmlcharrefreplace')
产量是:
1[secondary_label Output]
2b'st'
在任何情况下,Python都不会引发错误。
如前面的示例所示,‘忽略’会跳过无法编码的字符,‘代替’会用‘?’代替字符,而‘xmlcharrefplace’会用XML实体代替不可编码的字符。
解决 Unicode 错误
试图解密含有无法在指定的编码中表示的字符的字符串时发生 UnicodeDecodeError。
要创建此错误,您将尝试将字节字符串解码为无法解码的编码。
打开您的控制台并键入以下内容:
1>>> iso_supported = '§'
2>>> b = iso_supported.encode('iso8859_1')
3>>> b.decode('utf-8')
你会收到以下错误:
1[secondary_label Output]
2Traceback (most recent call last):
3 File "<stdin>", line 1, in <module>
4UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa7 in position 0: invalid start byte
如果您遇到此错误,您可以在解码()
函数中使用错误
参数,这可以帮助您解码字符串。
要证明这一点,打开您的Python控制台并输入以下代码:
1>>> iso_supported = '§A'
2>>> b = iso_supported.encode('iso8859_1')
3>>> b.decode('utf-8', errors='replace')
你的输出将是:
1[secondary_label Output]
2'�A'
然后输入以下内容:
1>>> b.decode('utf-8', errors='ignore')
你的输出将是:
1[secondary_label Output]
2'A'
在上一个示例中,使用代替
值在解码()
函数中添加一个字符
,并且使用忽略
没有返回任何在解码器(在这种情况下utf-8
)无法解码字节的地方。
在解码任何字符串时,请注意,您不能假设编码是什么。
结论
本文涵盖了如何在Python中使用Unicode的基本知识。您编码和解密字符串,使用NFD、NFC、NFKD和NFKC进行数据正常化,并解决了Unicode错误。您还在涉及分类和搜索的场景中使用了规范化表单。这些技术将帮助您处理使用Python的Unicode问题。作为下一步,您可以阅读 unicodedata模块文档来了解本模块提供的其他功能。 为了继续探索如何使用Python进行编程,请阅读我们的教程系列(How To Code in Python 3](https://www.digitalocean.com/community/tutorial_series/how-to-code-in-python-3)。