如何在 Python 中使用 Unicode

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

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错误。

前提条件

要遵循本教程,您将需要:

步骤 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

虽然字符串变量s1s2产生相同的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和``字符合并为一个单一的ô字符。

标准化形式 NFKDNFKC用于严格的规范化,可用于与搜索和 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'&#64262;'

在任何情况下,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)。

Published At
Categories with 技术
comments powered by Disqus