我遇到了一个我以前从未见过的新问题:我的客户正在向我们构建的项目添加文件,并且一些文件名中有特殊字符,因为有些单词是西班牙语。
例如,我正在测试的文件中有一个 á 。我在 css 文件中将该图像称为背景图像,但在 Safari 中它没有显示。但它适用于 FF 和 Chrome。
作为测试,我将链接粘贴到浏览器和同样的东西中。适用于 FF 和 Chrome,但 Safari 会抛出错误。所以我猜是语言字符在扔它?
Firefox 转换以下 url 并将 á 更改为 a%CC%81 并加载图像。
http://www.themediacouncil.com/test/nonascii/LA-MAR_Cebiche-Classico_foto-Henrique-Peron-470x120-1371827671.jpg
你可以看到它打破了...但是 FF 和 Chrome 将其转换为: http://www.themediacouncil.com/test/nonascii/LA-MAR_Cebiche-Cla%CC%81ssico_foto-Henrique-Peron-470x120-1371827671.jpg
你也可以在这里看到这个:http://jsfiddle.net/Md4gZ/2/
.testbox {
width:340px;
height:100px;
background:url('http://www.themediacouncil.com/test/nonascii/LA-MAR_Cebiche-Clássico_foto-Henrique-Peron-470x120-1371827671.jpg') no-repeat top left;
}
那么正确的处理方法是什么。我正在使用 PHP 和 WORDPRESS 进行开发。我宁愿不必告诉客户返回并用特殊字符替换所有文件。
任何帮助表示赞赏。谢谢!
我相信正在成为标准的是将非 ascii 字符转换为 UTF-8 字节序列,并将这些序列作为 %HH 十六进制代码包含在 URL 中。 á 字符是 U+00E1 (Unicode),它在 UTF-8 中构成两个字节
0xC3 0xA1
。因此,Clássico
将变为 Cl%C3%A1ssico
.
您从 Firefox 报告的转换
Cla%CC%81ssico
略有不同:它将 á 更改为后跟 U+0301,即组合重音字符。在 UTF-8 中,U+0301 生成 0xCC 0x81
.
您应该选择哪种表示形式——unicode“á”或“a 后跟组合重音”——取决于网络服务器需要什么来匹配正确的东西。在你的情况下,也许文件名实际上包含组合字符重音,这就是它起作用的原因(很难说)。
另一种处理非 ascii 拉丁字符的旧方法是使用 8 位拉丁字符集表示(ISO-8859-1 或类似的东西,例如 Windows-1252)并将其编码为一个字节。这将使
Clássico
变成Cl%E1ssico
。但是由于这只适用于拉丁字符集,并且对于它们的某些字符来说是模棱两可的,所以它很有希望并且可能会消失。
@njlarsson 已经 解释了 做什么好:
您从 Firefox 报告的转换 Cla%CC%81ssico 略有不同:它将 á 更改为后跟 U+0301,COMBINING ACUTE ACCENT 字符。在 UTF-8 中,U+0301 使 0xCC 成为 0x81。
更一般地说,我想知道为什么以及如何正确,所以这是我的想法。
当然除了原来的 - 西班牙用户不需要了解任何关于编码或解码的知识(除非他们是工程师或开发人员负责修复损坏的实现),另一个例子可以在Google JavaScript 风格指南中找到 ,独立于编程语言应用:
提示:永远不要仅仅因为担心某些程序可能无法正确处理非 ASCII 字符而降低代码的可读性。如果发生这种情况,则这些程序 broken 并且它们必须 fixed.
在高层次上,在 URL 中使用百分号
%
编码与 IETF RFC 1738 Section 2.2 一致。请注意,它没有说明 %
编码的含义,尽管按照惯例,网络是 UTF-8
从 Firefox 和 Chrome 在 2013 年的正确行为中可以看出。
在 PHP 中(在 Wordpress 中也是如此),文件名字符串可能未在
UTF-8
中编码。哪一个可能是一个自然的问题?
字符串可以最初以 UTF-8 编码的形式提供,解码为某种内部格式,也许是 UCS-2LE(这可以使某些字符串操作更快,但对其他字符串操作不利,例如表情符号😉,因为它们是在 basic 之外编码的多语言平面),然后重新编码为 UTF-8 打印。
继续使用 PHP,例如使用 mb_convert_encoding,这可能需要 php-cli 或服务器安装了 php-mbstring:
php > $encoded = "http://www.themediacouncil.com/test/nonascii/LA-MAR_Cebiche-Cla%CC%81ssico_foto-Henrique-Peron-470x120-1371827671.jpg";
php > $decoded = mb_convert_encoding($encoded, "UTF-8", "UCS-2LE");
php > $reencoded = mb_convert_encoding($decoded, "UCS-2LE", "UTF-8");
php > echo $reencoded;
http://www.themediacouncil.com/test/nonascii/LA-MAR_Cebiche-Cla%CC%81ssico_foto-Henrique-Peron-470x120-1371827671.jpg
或者字符串最初可能根本没有用 UTF-8 编码,这取决于它来自哪里,这里没有提供。
旁白:如果天真地打印
$decoded
字符串可能是无意义的——这看起来有点像Python 2“mojibake”问题:
php > echo $decoded; # UCS-2LE printed naively likely shows nonsense
瑨灴⼺眯睷琮敨敭楤捡畯据汩挮浯琯獥⽴潮慮捳楩䰯ⵁ䅍归敃楢档ⵥ汃╡䍃㠥猱楳潣晟瑯ⵯ效牮煩敵倭牥湯㐭〷ㅸ〲ㄭ㜳㠱㜲㜶⸱灪?
精确的底层细节和数学,假设一个人有足够的好奇心来思考计算机如何在物理上将数据表示为二进制或十六进制,可以在 StackOverflow 的其他地方找到。