不同的UTF-8签名用于相同的变音符号(变音符号) - 2种二进制方式来编写变音符号

时间:2012-08-27 18:24:03

标签: linux macos utf-8 diacritics dead-key

我有一个很大的问题,我在网上找不到任何帮助:

我将网页从OSX移动到Linux(两个系统都在de_DE.UTF-8中运行)并运行一个非常未知的问题: 有些文件不再被发现,但显然存在于硬盘上(明显)同名。所有这些文件都包含德国变音符号。

我拍了一张样本图片,从网页上复制了原始的请求-uri并直接调用它 - 同样的错误。重写文件名后,它有效。是的,我没有输错!

这令我感到惊讶,我看了一下apache-log,在那里我找到了这些条目:

192.168.56.10 - - [27/Aug/2012:20:03:21 +0200] "GET /images/Sch%C3%B6ne-Lau-150x150.jpg HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.1"
192.168.56.10 - - [27/Aug/2012:20:03:57 +0200] "GET /images/Scho%CC%88ne-Lau-150x150.jpg HTTP/1.1" 404 4205 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.1"

这是我要调查的内容......这是我在UTF8可预测http://www.utf8-chartable.de/中找到的内容:

ö   c3 b6   LATIN SMALL LETTER O WITH DIAERESIS
¨   cc 88   COMBINING DIAERESIS

我想你已经听说过死锁:http://en.wikipedia.org/wiki/Dead_key如果没有,请阅读文章。这很有意思;)

这是否意味着,OSX会将所有变音符号与字母分开保存?这是否真的意味着,OSX将角色ö保存为o和¨而不是使用组合结果的真实角色?

如果是,您是否知道我可以用来重命名这些文件的好脚本?这不是我从OSX迁移到Linux的第一页......

3 个答案:

答案 0 :(得分:11)

它与死键并不完全相同,但它是相关的。正如您所知,U + 00F6和U + 006F以及U + 0308具有相同的视觉效果。

事实上,在知道对待它们时,Unicode规则是基于分解的。字符数据库中有一个分解表,它告诉我们U + 00F6 规范分解为U + 006F,然后是U + 0308。

除了规范分解外,还存在兼容性分解。这些会丢失一些信息,例如²最终会被分解为2。这显然是一种破坏性的变化,但是当你想要有点模糊时搜索它是有用的(google知道搜索fiſh应该如何返回有关鱼的结果)。

如果在非组合字符后面有多个组合字符,那么我们可以重新排序,只要我们不重新排序同一类。当我们认为我们是否把一个cedilla放在某个东西然后是一个尖锐的口音,或者一个尖锐的然后是一个cedilla上并不重要时,这一点就变得清楚了。但是如果我们把一个急性和一个变音符号放在一封信上它显然很重要他们走的路。

由此,我们有4种规范化形式。在进行比较之前,将字符串放入适当的规范化形式,并且不会被绊倒。

NFD:通过规范尽可能地分解它来打破一切。按照它们的组合类的顺序重新排序组合字符,但是使用相同的顺序保持任何相同的类相对于彼此。

NFC:首先将所有内容都放入NFD。如果没有同一个类的早期版本,则继续按顺序查看组合字符。如果存在等效的单个字符,则替换它们,然后重新进行扫描以寻找进一步的构成。

NFKD:与NFD一样,但使用兼容性分解(破坏性更改,但如上所述对比较有用)。

NFD:做NFKD,然后根据NFC重新组合规范

还有一些重新组合被禁止在NFC中使用,因此如果Unicode中添加了更多字符,那么在一个版本的Unicode中有效NFC的文本不会停止为NFC。

在NFD和NFC中,NFC显然更为简洁。它不是最简洁的,但它是非常简洁的,可以以非常有效的流式方式进行测试和/或创建。

Mac OSX使用NFD作为文件名。因为他们是怪人。 (好吧,有比这更好的论据,他们只是没有说服我!)

Web角色模型使用NFC。*因此,您应该尽可能在Web上使用NFC。然而,盲目地将内容转换为NFC可能存在安全性因素。但如果它从你开始,它应该从NFC开始。

任何处理文本的编程语言都应该有一种将文本标准化为任何这些形式的好方法。如果你的不抱怨(或者你的是开源的,请捐款!)。

有关详细信息,请参阅http://unicode.org/faq/normalization.html;有关完整的详细信息,请参阅http://unicode.org/reports/tr15/

*为了更加有趣,如果您在XML或HTML元素内容的开头插入以长固体叠加(U + 0338)组合的内容,则会将标记的>转换为{{ 1}},将格式良好的XML变成乱码。出于这个原因,网络角色模型坚持认为每个实体本身必须是NFC,而不是以组合字符开头。

答案 1 :(得分:2)

谢谢,Jon Hanna在这里提供了很多背景信息!这对于获得完整答案很重要:从一种转换为另一种规范化形式的方式。

由于我的更改是在数据库中链接的文件系统(因为文件上传),我现在必须更新我的数据库转储。移动期间已经重命名了文件(可能是FTP-Client ......)

在Linux上转换字符集的命令行工具是:

  • iconv - 转换流的内容(可能是文件)
  • convmv - 转换目录中的文件名

charset utf-8-mac(如http://loopkid.net/articles/2011/03/19/groking-hfs-character-encoding中所述),我可以在iconv中使用,似乎只存在于OSX系统上,因此我必须将我的sql-dump移动到我的mac,转换它并将其移回另一种选择是使用convmv将文件重命名为NFD,但我认为这比将来更有阻碍。

工具convmv有一个内置(os-independent)选项来强制执行与NFC或NFD兼容的文件名:http://www.j3e.de/linux/convmv/man/

PHP本身(我的系统 - Wordpress所基于的语言)支持兼容性层: In PHP, how do I deal with the difference in encoded filenames on HFS+ vs. elsewhere?在我为我解决了这个问题之后,我会去编写一些测试,并且还可以向Wordpress和我使用的其他系统编写错误报告;)

答案 2 :(得分:1)

Linux发行版将文件名视为二进制字符串,这意味着不会假设编码 - 尽管图形shell(Gnome,KDE等)可能会根据环境变量,语言环境等做出一些假设。

另一方面,OS-X要求或强制(我忘记了)他们自己的UTF-8版本,并使用Unicode规范化将所有变音符号扩展为组合字符。

在Linux上,当人们在文件名中使用Unicode时,他们倾向于在变音符号时更喜欢带有预组合字符的UTF-8。