EUC-JP と Shift_JIS
弊社ブログユメのチカラ で、MySQL で ujis の 0x5C が sjis の 0x815F に変換されてしまう問題 が取り上げられていましたので、なぜ、そのような変換が行なわれるのか、そしてそのような実装が間違いとは言いきれない事を話たいと思います。
MySQL での ujis と sjis は、それぞれ、IANA で定義されている EUC-JP と Shift_JIS に相当します。
まずは、それぞれの定義を見てみましょう。
EUC-JP の定義
Name: Extended_UNIX_Code_Packed_Format_for_Japanese
MIBenum: 18
Source: Standardized by OSF, UNIX International, and UNIX Systems
Laboratories Pacific. Uses ISO 2022 rules to select
code set 0: US-ASCII (a single 7-bit byte set)
code set 1: JIS X0208-1990 (a double 8-bit byte set)
restricted to A0-FF in both bytes
code set 2: Half Width Katakana (a single 7-bit byte set)
requiring SS2 as the character prefix
code set 3: JIS X0212-1990 (a double 7-bit byte set)
restricted to A0-FF in both bytes
requiring SS3 as the character prefix
Alias: csEUCPkdFmtJapanese
Alias: EUC-JP (preferred MIME name)
Shift_JIS の定義
Name: Shift_JIS (preferred MIME name)
MIBenum: 17
Source: This charset is an extension of csHalfWidthKatakana by
adding graphic characters in JIS X 0208. The CCS's are
JIS X0201:1997 and JIS X0208:1997. The
complete definition is shown in Appendix 1 of JIS
X0208:1997.
This charset can be used for the top-level media type "text".
Alias: MS_Kanji
Alias: csShiftJIS
ここで注目すべき点としては、0x00~0x7F の部分で、EUC-JP は US-ASCII、Shift_JIS は JIS X 0201 ラテン文字 (ローマ文字) となる点です。
MySQL での文字コード変換は、Unicode 経由での変換となっていますので、IANA の定義にしたがって、EUC-JP と Unicode、Shift_JIS と Unicode の対応関係を表にすると次の様になります。(問題になるコードポイントのみピックアップ)
| EUC-JP | Unicode |
|---|---|
| 0x5C REVERSE SOLIDUS | U+005C REVERSE SOLIDUS |
| 0x7E TILDE | U+007E TILDE |
| 0xA1C0 REVERSE SOLIDUS | U+FF3C FULLWIDTH REVERSE SOLIDUS |
| 0xA1EF YEN SIGN | U+00A5 YEN SIGN |
| 0xA1B1 OVERLINE | U+203E OVERLINE |
| Shift_JIS | Unicode |
|---|---|
| 0x5C YEN SIGN | U+00A5 YEN SIGN |
| 0x7E OVERLINE | U+203E OVERLINE |
| 0x815F REVERSE SOLIDUS | U+005C REVERSE SOLIDUS |
| 0x818F YEN SIGN | U+FFE5 FULLWIDTH YEN SIGN |
| 0x8150 OVERLINE | U+FFE3 FULLWIDTH MACRON (JIS規格参照) |
この対応表を使って、EUC-JP の 0x5C を Shift_JIS に変換すると、どうなるか見てみましょう。
| EUC-JP (ujis) | → | Unicode | → | Shift_JIS (sjis) |
|---|---|---|---|---|
| 0x5C | → | U+005C | → | 0x815F |
EUC-JP の REVERSE SOLIDUS (0x5C) が Shift_JIS の REVERSE SOLIDUS (0x815F) に変換されています。これは、MySQL で ujis の 0x5C が sjis の 0x815F に変換される動作と同じですね。
MySQL の変換は、利用者からしてみれば不具合でしかないわけですが、上記のように IANA の定義に従ってまじめに実装を行なった結果だと分かるかと思います。
ただし、MySQL では Shift_JIS (sjis) の 0x5C YEN SIGN を EUC-JP (ujis) の 0xA1EF YEN SIGN に変換せずに、0x5C REVERSE SOLIDUS に変換しているので、規格に厳密に実装しているわけでも無さそうです。
なぜ、そのような実装になるのか思い当たるフシはありますが、ここでは省略させてもらいます。
mysql> SELECT HEX(CONVERT( _sjis 0x5C using ucs2 ));
+---------------------------------------+
| HEX(CONVERT( _sjis 0x5C using ucs2 )) |
+---------------------------------------+
| 005C |
+---------------------------------------+
1 row in set (0.00 sec)
EUC-JP、Shift_JIS の実装に関しては、伊藤隆幸さんのホームページの 従来の文字コードとUnicodeの対応に関する諸問題 > 6. ASCIIとJIS X 0201ローマ文字 で説明されているように、JIS X 0208や JIS X 0212 はなるべく FULLWIDTH に追いやってしまうという事にすれば、今回のような文字化けを回避可能となります。
cp932 と eucjpms (eucJP-ms) に関しては、JIS X 0208 や JIS X 0212 を FULLWIDTH に追いやってしまう事に加えて、JIS X 0201 ラテン文字を Unicode の U+0000~U+007F のコードポイントに対応付けするという事をして、Unicode 以前の US-ASCII と JIS X 0201 ラテン文字の扱いと同じ解釈で処理が行なえるようになっています。
規格遵守をしようと思って実装を行なうと、実際には利用者にとっては使えないものを作ってしまうという不幸をなくす為にも、規格遵守した時に矛盾が生じないように規格の改正などが必要かもしれません。



まず、JIS X 201を改正すべきなんじゃよー。
1.規格をASCII部分と半角カタカナ部分の2つに分岐させる
2.ASCII部分はASCIIと完全に同じ規定にする。Yenとかoverlineとかステステ。ただし、過去の互換性からフォント表示をYenとかoverlineとかでしても規格不一致とはみなさない。という一文だけ追加する
現実的にはすべての文字コードは7bit部分にASCIIを期待していて、世の中のソフトもみんなそう実装されているのに、いや、実は規格上の定義はそうではなくて・・・とかヘンな話しをするから、混乱するのじゃよー。
と、極論を吐いてみるテスト
投稿: kosaki | 2006年10月18日 (水) 23:25
現実主義者としては、仮に規格を改正しても、現在の実装は残るし現場で困っている人を救えない、なんてことを思っていて、じゃあ、なんで規格を改正するんだよと問われれば、それは規格原理主義者の口を(あぐ、うわ、ぐはああああ…)
極論返し。
しかし、50円なりを¥50と表示するの\50では全然違うしなあ。
投稿: hyoshiok | 2006年10月19日 (木) 10:17
規格違反を指摘するのが簡単であっても、規格違反にならず実用的に使えるような実装を行なう事は、現状では、困難であるという事を認識していただければと思っています。
ISO/IEC 10646(≒Unicode) は、ISO/IEC 646 の各国版との互換性を考え、U+0000 から U+007F は ISO/IEC 646 IRV(US-ASCII) 決め打ちにしなければいいだけの話なのかもしれません。
投稿: moriyama | 2006年10月19日 (木) 11:32