Python UTF8编码

Soy*_*cis 2 python encoding utf-8

我看过有关Python和编码的其他问题,但还没有找到解决我问题的方法。这里是:

我有一个小脚本,试图比较2个文件列表:

  1. 文本文件中给出的列表,应该以UTF8编码(至少Notepad ++会这样检测到该列表)。

  2. 我建立的目录清单如下:

    local = [f.encode('utf-8') for f in listdir(dir) ]
    
    Run Code Online (Sandbox Code Playgroud)

但是,对于某些字符,我没有得到相同的表示形式:在HEX编辑器中查看时,我发现在1中,字符é由给出,65 cc而在2中,字符由c3 a9... 给出。

我想要的是使它们具有相同的编码,无论它是什么。

Mat*_*lia 5

您的第一个序列不完整- cc是两个字节的UTF-8序列的前缀。最有可能的完整序列是65 cc 81,实际上是字符e(0x65),后跟一个COMBINING ACUTE ACCENT(0x301,在UTF-8中表示为cc 81)。

相反,另一个序列是带有 ACUTE字符(0xe9,以c3 a9UTF-8 表示)的预组合拉丁文小写字母E。您会在链接的页面中注意到其分解恰好是第一个序列。

Unicode规范化

现在,在Unicode中,有许多不同序列的实例在图形和/或语义上是相同的,虽然将UTF-8流视为不透明的二进制序列通常是一个好主意,但是如果您想这样做,则会带来问题搜索或索引-寻找一个序列与另一个序列不匹配,即使它们在图形和语义上是相同的。因此,Unicode定义了四种类型的规范化,可用于“平化”这种差异并从组合形式和分解形式中获得相同的代码点。例如,在这种情况下,NFC和NFKC归一化格式将为您的两个序列提供0xe9代码点,而NFD和NFKD将为0x65 0x301分解形式。

要在Python中执行此操作,您首先需要decode将UTF-8 str对象转换为unicode对象,然后再使用unicodedata.normalize方法。

重要说明:除非您正在实现“智能”索引/搜索,否则不要进行标准化,并且仅将标准化数据用于此目的-即对标准化的索引和搜索,但要向用户存储/提供原始格式。规范化是一种有损操作(尤其是某些形式),盲目地将其应用于用户数据就像在陶瓷店里用大锤进入一样。

文件路径

好的,这通常是关于Unicode的。谈论文件系统路径既简单又复杂。

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

终端中名为é的两个文件

因此,在原则上处理文件路径时,您永远不要规范化 -同样,文件路径是不透明的代码点序列(实际上,在Linux上是不透明的字节序列),不应混淆。

但是,如果您收到的列表和要处理的列表进行了不同的规范化(这可能意味着该列表已通过损坏的软件传递,可以“有帮助”地规范组成/分解的序列,或者手动输入了名称) ),则必须执行一些标准化匹配。

如果要处理类似的情况(按定义划分),我将执行以下操作:

  • 首先尝试完全匹配;
  • 如果失败,则尝试将标准化文件名与set包含目录标准化内容的进行匹配;请注意,如果多个原始名称映射到相同的规范化名称,您与之完全不匹配,则您将无法知道哪一个是“正确的名称”。

脚注

  1. Linux本地文件系统都使用基于8位字节的路径-内核可以在任何编码下使用它们,而内核并不在乎,尽管最近的系统通常使用UTF-8。Windows本地文件系统将改为使用16位基于单词的路径,这些路径名义上包含UTF-16(最初为UCS-2)值。
  2. 在Windows上,在API级别上有点复杂,因为存在执行代码页转换的整个ANSI API混乱,并且Win32路径的不区分大小写的匹配增加了更多级别的复杂性,但是在内核和文件系统级别上则完全不透明2个字节的WCHAR字符串。