第一个序列是不完整的-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规范化forma将给出两个序列的0xe9码位,而NFD和NFKD将给出0x65 0x301分解形式。在

要在Python中实现这一点,首先要将UTF-8 str对象unicode对象,然后使用unicodedata.normalize方法。在

重要注意事项除非您正在实现“智能”索引/搜索,否则不要规范化,并且仅将规范化数据用于此目的-即索引和搜索规范化,但应存储/向用户提供原始表单。规范化是一种有损操作(某些形式尤其如此),盲目地在用户数据上应用它就像在陶器店里用大锤进入。在

文件路径

一般来说,Unicode是可以的。讨论文件系统路径既简单又复杂。在

根据原则,几乎所有Windows和Linux上的常见文件系统都将路径视为不透明字符1序列(对目录分隔符和NUL字符进行模化),而不应用特定的规范化形式。因此,在一个给定的目录中,可以有两个文件名,看起来相同,但确实不同:


因此,在原则上处理文件路径时,您永远不应该规范化—同样,文件路径是一个不透明的代码点序列(实际上,在Linux上是一个不透明的字节序列),不应该弄乱它。在

但是,如果您接收到的列表和您必须处理的列表是不同的规范化的(这可能意味着要么它是通过一个损坏的软件“有用地”规范化组合/分解的序列,要么名称是手工输入的),那么您就必须执行一些规范化的匹配。在

如果我要处理一个类似的(被定义打破了)场景,我会这样做:首先尝试精确匹配

如果失败,请尝试将规范化文件名与包含目录规范化内容的set匹配;请注意,如果多个原始名称映射到同一个规范化名称和,那么您无法确切地匹配它,您无法知道哪一个是“正确的”。在

脚注Linux本机文件系统都使用基于8位字节的路径-它们可能采用任何编码方式,内核并不在乎,尽管最近的系统通常碰巧使用UTF-8;Windows本机文件系统将使用基于16位字的路径,这些路径名义上包含UTF-16(最初是UCS-2)值。在

在Windows上,API级别的复杂程度要高一些,因为整个ansiapi都在执行代码页转换,而不区分大小写的Win32路径匹配又增加了一个compli级别但是在内核和文件系统级别,它都是不透明的2字节WCHAR字符串。在