1

那里有很多关于编码我们的问题,但我仍然无法解决我的问题。

想象一下,我在一个压缩的 ZIP 文件中有三个文件:

Übersicht.pdf finalePräsentation münchen

我想解压缩这些文件,所以我这样做:

with zipfile.ZipFile("path/result.zip", "r") as zip_ref:
    zip_ref.extractall("/path/")

文件名看起来像废话:

在此处输入图像描述

我的研究表明,文件名基本上是字节串,操作系统不可能看到编码是什么。但我仍然想知道是否有任何方法可以纠正文件名的问题,以便正确显示德语“Umlaute”。

我试图改变这样的编码:

    with zipfile.ZipFile(save_as, "r") as zip_ref:
        print(zip_ref.namelist())
        encoded_strings = [s.encode("utf-8") for s in zip_ref.namelist()]
        print(encoded_strings)
        zip_ref.extractall(dest)

我尝试了这个latin-1iso其他一些编码和字节字符串实际上被不同地解释,但总是神秘的。因此,我问这个问题,看看是否有一种简单的方法来解决这个问题。

非常感谢提前,非常感谢帮助

编辑:locale给我以下输出:

LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL="en_US.UTF-8"

hexdump第一个文件开头的内容如下:

0000000 25 50 44 46 2d 31 2e 34 0a 25 93 8c 8b 9e 20 52
0000010 65 70 6f 72 74 4c 61 62 20 47 65 6e 65 72 61 74
0000020 65 64 20 50 44 46 20 64 6f 63 75 6d 65 6e 74 20
0000030 68 74 74 70 3a 2f 2f 77 77 77 2e 72 65 70 6f 72

回声*.pdf | xxd | 头给了我这个:

00000000: 6669 6e61 6c65 5072 c3a4 7365 6e74 6174  finalePr..sentat
00000010: 696f 6e2e 7064 660a                      ion.pdf.
00000000: 6dc3 bc6e 6368 656e 2e70 6466 0a         m..nchen.pdf.
00000000: c39c 6265 7273 6963 6874 2e70 6466 0a    ..bersicht.pdf.
4

2 回答 2

1

如果您没有找到原始编码,您可以随时尝试回退到 ascii:

[unicodedata.normalize('NFKD', s).encode('ascii', 'ignore') for s in zip_ref.namelist()]

使用内置库unicodedata

于 2021-09-24T10:37:28.123 回答
1

感谢您的十六进制转储。使用更新的数据,文件名似乎完全是使用可能的代码页 1252运行的 mill mojibake

destination_file = filename.encode('cp1252').decode('utf-8')

在您更新您的问题之前,我最初的猜测保留在下面,可能很有趣和/或有启发性。


您的屏幕截图有点模糊,但它看起来模糊地像文件名被编码为Windows 代码页 437

>>> import unicodedata
>>> unicodedata.normalize('NFKD', "Übersicht.pdf").encode('utf-8')
b'U\xcc\x88bersicht.pdf'

检查字符代码0xcc它转换为编码 cp1125、 cp437、cp720、cp737、cp775、cp850、cp852、cp855、cp856、cp857、cp858、cp860、cp861、cp8662、cp863、 、cp866 和 cp869;和0x88转换为 ê‎ ( U+00EA in cp437, cp720, cp850, cp857, cp858, cp860, cp861, cp863, 和 cp865。交叉点有多种编码,但 437 是迄今为止最常见的PKzip 是什么时候发明的。

(╠ 是双笔画的,而您的屏幕截图看起来更像是单笔画的版本,但这可能只是字体设计和/或图片不清楚的问题;并且结论足以令人信服,我将继续使用.)

(披露:链接是我自己的页面。)

假设这个分析是正确的,并且假设zip库将名称作为字节字符串提供给您,您应该能够简单地使用解码它们

destination_file = filename.encode('latin-1').decode('cp437')

Latin-1 上的绕行模糊地将每个字符代码转换为相应的字节值(回想一下,Latin-1 在前 256 个字符中与 Unicode 兼容,但它是纯 8 位字符编码),因此我们可以将其映射回来通过使用正确的编解码器将其解码为 Unicode。

于 2021-09-24T11:55:29.783 回答