我查看了有关 Python 和编码的其他问题,但还没有找到解决问题的方法。这里是:
我有一个小脚本,它试图比较 2 个文件列表:
local = [f.encode('utf-8') for f in listdir(dir) ]
但是,对于某些字符,我没有得到相同的表示:在 HEX 编辑器中查看时,我发现在 1 中,字符
é
由 65 cc
给出而在 2 中,它由 c3 a9
给出...我想要的是让它们具有相同的编码,无论它是什么。
最佳答案
您的第一个序列不完整 - cc
是两字节 UTF-8 序列的前缀。最有可能的是,完整的序列是 65 cc 81
,这确实是字符 e
(0x65) 后跟 COMBINING ACUTE ACCENT (0x301,在 UTF-8 中表示为 cc 81
)。
另一个序列是预先组合的 LATIN SMALL LETTER E WITH ACUTE字符(0xe9,在 UTF-8 中表示为 c3 a9
)。您会在链接页面中注意到它的分解正是第一个序列。
Unicode 规范化
现在,在 Unicode 中有许多不同序列的实例在图形和/或语义上是相同的,虽然将 UTF-8 流视为不透明的二进制序列通常是个好主意,但如果你想这样做,这会带来问题搜索或索引 - 寻找一个序列不会匹配另一个,即使它们在图形和语义上是相同的。因此,Unicode 定义了 four types of normalization ,可用于“展平”这种差异并从组合形式和分解形式中获得相同的代码点。例如,在这种情况下,NFC 和 NFKC 规范化形式将为您的两个序列提供 0xe9 代码点,而 NFD 和 NFKD 将提供 0x65 0x301 分解形式。
要在 Python 中执行此操作,您首先需要 decode
你的 UTF-8 str
反对unicode
对象,然后使用 unicodedata.normalize
方法。
重要提示 :除非您正在实现“智能”索引/搜索,否则不要规范化,并且仅将规范化数据用于此目的 - 即索引和搜索规范化,但将原始表单存储/提供给用户。规范化是一种有损操作(某些形式尤其如此),盲目地将其应用于用户数据就像用大锤进入陶器店一样。
文件路径
好的,这通常是关于 Unicode 的。谈论文件系统路径既简单又复杂。
原则上,Windows 和 Linux 上几乎所有常见的文件系统都将路径视为 。不透明 character1 序列(以目录分隔符和可能的 NUL 字符为模),没有应用特定的规范化形式2。因此,在给定目录中,您可以拥有两个看起来相同但实际上不同的文件名:
因此,当按照原则处理文件路径时,您永远不应该规范化——同样,文件路径是一个不透明的代码点序列(实际上,在 Linux 上是一个不透明的字节序列),不应该被弄乱。
但是,如果您收到并且您必须处理的列表被不同地标准化(这可能意味着它已经通过一个损坏的软件传递,该软件“有用地”标准化组合/分解的序列,或者名称是手动输入的) 你必须执行一些标准化匹配。
如果我要处理类似的(根据定义打破)场景,我会做这样的事情:
set
匹配。包含目录的规范化内容;请注意,如果多个原始名称映射到同一个规范化名称并且您不完全匹配它,您将无法知道哪个是“正确的”。 脚注
WCHAR
字符串。 关于Python UTF8 编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44897977/