Python 了解 unicode 转换

Python understanding unicode conversion

我有一个文本数据集存在一些编码问题。 作者指示做的事情:

for line in fpointer:
    line.encode('latin-1').decode('utf-8')

解决问题。

我想看看为什么需要它,我在修复之前打开了文件,看到了这一行:

103 But in Imax 3-D , the clichés disappear into the vertiginous perspectives opened up by the photography .

转换后变成:

103 But in Imax 3-D , the clichés disappear into the vertiginous perspectives opened up by the photography .

有道理。

但我不明白是什么导致了最初的问题,修复是如何进行的?

我引用了 unicode python link : https://docs.python.org/3/howto/unicode.html

我还检查了字符及其值:

é 的 utf-8 编码是 c3a9,Ã 的 iso-8859-1 编码是 c3,© 是 a9。

有点道理,但我无法建立联系。

该行究竟是如何存储在原始文件中的,代码片段是如何修复它的?

原始文本是用utf-8编码的,但一些进程将其解码为latin1,然后再次将其编码为utf-8。

因此,要获得原始文本,您必须反转此过程:将文件中的文本解码为 utf-8(这不包含在您的代码段中,但我猜您使用 utf-8 编码打开它),然后将其编码为 latin1,然后再次解码为 utf-8。

那么 - 发生的事情是您的文本 "double-encoded" 为 utf-8。

因此,在生成您拥有的数据的过程中的某个时刻,已经具有“é”的“\xc3\xa9”内部表示的文本被解释为 latin-1,并且re- 从 "latin1"(其中“\xc3\xa9”代表“É”)转换为 utf-8,这样每个字符都被扩展为两个字节,变成:“\xc3\x83”“\xc2\xa9”(“É”的 utf-8)。正如@Novoselov 在另一个答案中所说的那样,这种损坏可能是由于您打开文件以作为文本读取,而没有在 Windows 上指定编码:Python 会认为该文件是 "latin-1" ,默认 Windows 编码,因此读取其中的每个字节,它是 utf-8 文本序列的一部分,作为单个 latin-1 字符。

修复的内容:您的系统设置已经配置为将文本读取为 utf-8 - 因此当您在 for 循环中获得这些行时,您获得了 Python-3 个字符串(Python -2 unicode) 正确解释为文本文件中的 UTF-8 字符。所以 4 字节序列变成了 2 个文本字符。现在,"latin1" 编码的一个特点是它是 "transparent":它相当于在文本字节中根本不执行任何转换。换句话说,在 Python 的 Unicode 内部表示中,由适合单个字节的值表示的每个字符成为编码字节字符串中的单个字节。 (并且每个值不适合字节的字符根本无法编码为 Latin-1,从而产生 Unicode-Encode 错误)。

因此,在 "transparent" 编码步骤之后,您有代表文本的字节 - 这次只有 "one pass" 的 utf-8 编码。并将这些字节解码为 "utf-8" 为您提供了文件的正确文本。

再次:

这是原文: "cliché"。编码成UTF-8就变成了这样: b'陈词滥调\xc3\xa9' 但是创建文件的原始进程认为这个序列是 latin-1,所以将两个 > 0x80 字符都重新转换为 utf-8: b'陈词滥调\xc3\x83\xc2\xa9'。 这就是打印为 "cliché"

的内容

在阅读时,Python3 写道: b'clich\xc3\x83\xc2\xa9' 从磁盘,returns 给你 "cliché" 作为 (unicode) 文本。 您将其编码为字节,并通过调用 "encode('latin-1'). Finally you then "decode" 获取 b'clich\xc3\xa9' 从 "utf-8" 获取文本 "cliché"。

Python3 不会轻易让一个人像这样破坏文本。要从文本转到您拥有的不正确版本,还必须使用 "transparent" 编码 "latin-1" - 这是一个示例:

In [10]: a = "cliché"

In [11]: b = a.encode("utf-8")

In [12]: b
Out[12]: b'clich\xc3\xa9'

In [13]: c = b.decode("latin1").encode("utf-8")

In [14]: c
Out[14]: b'clich\xc3\x83\xc2\xa9'

根据您的评论,您说您在 Python 3 中打开一个文本文件,但未指定任何编码。在这种情况下,Python 使用 system 编码,即 Windows 上的 Latin1。

这足以解释如果文件最初是 utf8 编码的,您会得到什么。但恕我直言,正确的方法是在 open 函数中指定文件编码:

fd = open(filename, encoding='utf8')

这样就可以直接得到正确的字符,不需要编解码校正。