日文编码下反斜线是¥的一些考据
为什么?这个问题困扰很久,虽早就发现——以前玩日语游戏时候看到的——但一直不得其解。包括各种日语输入法,按反斜线键出来的是日元符号(yen sign)而不是反斜线。
那么查看一下Backslash的维基百科页面:
In the Japanese encodings ISO 646 (a 7-bit code based on ASCII), JIS X 0201 (an 8-bit code), and Shift JIS (a multi-byte encoding which is 8-bit for ASCII), the code point 0x5C that would be used for backslash in ASCII is instead rendered as a yen mark (¥)…
困惑一下就解决了!简言之就是不同字符集下面的冲突,根据Windows Codepage: 932 (Japanese Shift-JIS)上的记录,很清楚可以看到在Shift JIS下0x005c被¥占据。因为当年的字符集位置比较紧张,或许是迫于无奈,日韩两国的默认编码系统不得不这样做。在Unicode中,0x5c还是U+005c,而日元符号¥则是U+00a5,平时我们用中文输入法打出来的¥则是U+FFE5。根据上面Backslash的维基页面所说,还能知道:
- 虽然这是个问题,但由于历史悠久而影响过于广泛,目前来看改回来不太可能。甚至Windows的明朝体等日文系统默认字体会在Unicode下把U+005c也渲染成日元符号,以保持和之前一致。
- 韩语系统下,则有类似的问题,反斜线被韩元符号₩代替。
Windows Codepage: 949 (Korean)
反斜线一直被用于表示本地目录路径的分隔符,所以之前在看日本人写的开源项目时候也注意到这奇怪的不同点,同时也知道自己当时玩游戏时候看到的¥并非乱码。那么难道日韩两国人的广大人民群众们用着和其他国家人用不同的分隔符而不觉得别扭吗?根据
When is a backslash not a backslash?一文的考据,这两国的一般人不太关心这个,而IT行业的人虽然觉得别扭,但“怎么改呢。毕竟已经用了这么久,习惯了。”
实际上,这还不仅是使用习惯和视觉上适应与否的问题,试想一下如果在日韩编码的系统中如果确实要显示货币符号,而文件系统认为是反斜线又如何,比如AIX shows the Japanese Yen symbol as a backslash;而反过来说,希望显示反斜线而被渲染成了货币符号的问题也是存在的。解决办法只能是手动判断当前的字符编码类型,如果是Shift JIS或者其他什么会引起混淆的类型的话,再进行手动转换。而那个反斜线被错误渲染的问题,是Firefox当年(2004年)1.0版本RC前发现在utf-8编码网页中的,comment中有日本人现身说法(8楼),提到就算是日本人也对具体怎么处理存在分歧:
- 永远不替换0x5c到U+a5
- 在编码为Shift_JIS、EUC-JP和IS0-2022-JP情况下进行替换
- 用户决定是否替换
最终的解决方案不在这三种内,而是限定了语言、替换选项和字符集非unicode时才进行替换(减少false positive)。在もじら組上,甚至有更早的Firefox相关问题报告,bug生存期超过7个月,讨论数100+。可以看到Firefox内处理这个问题的代码类似于:
818 if (mLanguageSpecificTransformType ==
819 eLanguageSpecificTransformType_Japanese) {
820 for (PRInt32 i = 0; i < aLen; i++) {
821 if (aText[i] == 0x5C) { // BACKSLASH
822 aText[i] = 0xA5; // YEN SIGN
正是由于有这样的转换存在,我们所使用的编程平台,在进行国际化编程时都会存在特定语言的Unicode勘误(collation)功能。所以对于现在的程序员而言这已并非什么大问题。当然,平时写代码时,也会时刻注意不自己硬编码,而使用系统决定字符:例如.net上是Path.PathSeparator或者用Path.Combine合并路径;Python中则用os.sep,等等。
对软件进行国际化和本地化是很多程序员经常忽视,却又是非常重要的一环。有空的话会把之前工作中见到的和亲身处理过的相关问题列一些出来,现在看看非常有趣但当时处理的时候棘手得很。