情况: 我有一个小型 NAS 服务器,支持 FTP、SHH、Samba(和其他)协议。 我想制作 python 脚本,通过 FTP 将文件从“源目录”(从桌面 PC - Windows 7)复制到 NAS 上的“目标目录”。
问题: ftp.mkd(“安德烈”) 制作正确的uft-8目录
总指挥: 当我创建同一目录“André”时
解决方案: 如何将“André”转换为“André”?在将字符串传递给 ftp.mkdir() 之前,我必须对它做什么? (脚本采用utf-8)
这似乎是 Unicode 字符串规范化的问题。
Unicode 通常允许相同的字符由不同的底层二进制序列表示。例如,“é”(e-acute)可以用单个代码点 U+00E9(带有锐音符号的拉丁小写 e)表示,也可以用两个代码点序列 U+0065(拉丁小写 e)U+0301(组合)表示尖锐的口音)。
>>> 'Andr\u00E9'
'André'
>>> 'Andr\u0065\u0301'
'André'
它们看起来相同,并且根据 Unicode 规范,它们都是表示 e-acute 的可接受方式,但您可以在幕后看到二进制表示不同。
>>> bytes('Andr\u00E9', 'utf-8')
b'Andr\xc3\xa9'
>>> bytes('Andr\u0065\u0301', 'utf-8')
b'Andre\xcc\x81'
您需要规范化底层表示。 Unicode 提供四种不同的标准化形式:NFD、NFC、NFKD 和 NFKC。
D 形式将字符分解为多个码点形式,C 形式将字符组合为单码点形式。
K 代表兼容性(因为 C 已经被用来代表组合)。 K 形式会将连字分解为单独的字符,因此您几乎肯定要使用 K 形式(尽管它对于您的“André”示例似乎没有什么区别)。
至于 C 和 D 形式之间的选择,回想一下我们之前在使用 e-acute 的组合单码点形式时看到的二进制输出:
>>> bytes('Andr\u00E9', 'utf-8')
b'Andr\xc3\xa9'
并注意 U+00C3 = à 且 U+00A9 = ©
它仍应显示为“André”而不是“André”,但这是软件的一个单独问题,该软件要么不支持 Unicode,要么其编码设置配置错误。
重要的一点是,如果您想要“André”行为,则应该使用 C 形式进行规范化。
简而言之,使用NFKC形式进行标准化。
unicodedata.normalize
:
>>> from unicodedata import normalize
>>>
>>> bytes(normalize('NFKC', 'Andr\u00E9'), 'utf-8')
b'Andr\xc3\xa9'
>>> bytes(normalize('NFKC', 'Andr\u0065\u0301'), 'utf-8')
b'Andr\xc3\xa9'
或者,就您而言:
from unicodedata import normalize
ftp.mkd(normalize('NFKC', 'André'))