我将一个页面从一个网站从OSX移动到Linux(两个系统都在de_DE.UTF-8中运行)并运行一个非常未知的问题:
有些文件不再被发现,但显然存在于硬盘上(明显)同名.所有这些文件都包含德语变音符号.
我拍了一张样本图片,从网页上复制了原始的request-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和¨而不是使用组合结果的真实角色?
解决方法
事实上,在知道对待它们时,Unicode规则是基于分解的.字符数据库中有一个分解表,它告诉我们U 00F6规范地分解为U 006F,然后是U 0308.
除了规范分解之外,还存在兼容性分解.这些丢失了一些信息,例如²最终会被分解为2.这显然是一种破坏性的变化,但是当你想要有点模糊时搜索是有用的(谷歌如何知道搜索鱼应该返回关于鱼的结果) .
如果在非组合字符后面有多个组合字符,那么只要我们不重新排序同一类的字符,我们就可以对它们进行重新排序.当我们认为我们是否把一个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)组合的内容,则会转换为>将标签转换为≯,将格式良好的XML转化为乱码.出于这个原因,Web角色模型坚持认为每个实体本身必须是NFC而不是以组合字符开头.