¥を巡る不都合な真実 - モディファイド・シフトJISという化石
パソコンの世界で漢字を含む日本語を扱えるようにするために、処理が煩雑になるJISコードをそのまま扱うのではなく、文字コードセットの切り替え処理が不要になるシフトJISというコードが発明されました。
このコードがどのような経緯でMS-DOSなどで採用されたのかは、あまり詳しくわからないのですが、この文字コードは規格ではなくあくまで実装に過ぎなかったので、メーカー独自の判断で構わないと思われていたようです。
MULTI16 - 遂に三菱電機もパソコンを出した
実際、MS-DOSで採用されたシフトJISも「コードページ932」というOEMコードに過ぎません。
Windowsコードページの謎
この文字コードが身近に使われるようになったのは、MS-DOSが日本語に対応した1983年にリリースされた「日本語MS-DOS Ver2.x」からだと思います。この段階で階層化ディレクトリもサポートされ、CP/Mから継承したコマンドオプションは”/”で始まるというルールが仇となりパスの区切り文字がUNIXなどで使われていた”/”の代わりに”\”(日本語環境だと”¥”)が使われ、何だか嫌な雰囲気が漂っていたのですが、当時の開発言語にC言語が使われていることは殆どなく、シフトJISという日本語コードにとって不都合な真実は露見していませんでした。
ちょうどその頃、学術分野で使われていたOSに過ぎなかったUNIXが広くビジネス分野にも使われるようになりつつあり、そのライセンス形態が問題となりつつありました。1981年にはサン・マイクロシステムズが登場し、BSDベースのSunOS1.0を開発し、1982年にはAT&TがVersion7をベースにしたSystemⅢをリリースしました。タイミング良く1983年にAT&Tの独占禁止法問題の決着がつき、AT&T主導でUNIXの商用化が進められることになりました。
これを受けて日本においても日本語が扱えるUNIXが求められるようになり、最初は各メーカーが独自の対応を行っていたようです(そういえばJUSも1983年創設ですね)。日本語を使えるようにするためにやることは実にいろいろあったのですが、最初のハードルはシステムの8ビットスルーだったことは間違いないでしょう。この段階では日本語の文字コードはJISしか無かったのですが、やはりこれをそのまま実装するには処理が煩雑になりすぎるので、目の前で既に使われているシフトJISを採用しようとする動きもありました。
UNIXといえば、その大部分はC言語で記述されていますから、ここでシフトJISの不都合な真実が発覚します。シフトJISコードは漢字第2バイトとして制御文字である 0x00~0x1f、0x7fを使わないようにするだけではなくプロトコルなどで特別な処理が予想される空白文字や記号で使われる0x20~0x3f(そして0xfd~0xffも)使わないようにしていました。ただ記号の中でももっと後ろのコードを割り当てられている”[]^_{|}~”については第2バイトで登場することもあるわけです。なんとここにC言語で文字列をエスケープする記号である”\”が入っていたわけです。
シフトJISを理解しない既存の処理系では当然のように”\”を見つけると、そこで処理をエスケープするのだと理解して、その後ろに続く文字を解釈します。それが漢字コードの一部であるとは知りません。ですから漢字第2バイトが0x5c”\”となる特定の文字が含まれると、その後ろにあるバイト列をエスケープとして処理しようとし本来の意味が失われることとなります。運が良ければ数文字の文字が化けるだけで済みますが、組み合わせのよっては、その後のすべての文字が意味を失ってしまうこともあります。対象がソースコードで、文字列リテラルの区切りである「”」が失われたり、コメントの「//」や「/*」「*/」が誤認されると何が起こるかを想像してみてください。
Shift_JIS
対象がソースコードであるのであれば、あらかじめ文字列を見つけたらバイト単位で走査して0x5cを見つけるたびに0x5cを挿入することで、エスケープ処理が行われるのを防ぐコードに直せますが、この処理はソースコード以外でもファイル処理や正規表現などにおいても働くことがあり、それに対応するためにデータを書き換えたり、表現を変更するのは現実的ではありません。そのような訳で、これら特定の文字が使われることだけで嫌われる不幸な文字になってしまったのですが「ソースコード」であるとか「一覧表」という文字が尽く駄目なわけですから無視するわけにもいきません。もちろん、これらの文字が自分の名前に含まれる人にとってはいったい何の恨みがあるのかという話です。
そこで当時のごく一部のメーカーがとった対応というのが、シフトJISというのは、あくまでJISをシフトしたものに過ぎないので、この0x5cもシフトしてしまえという実に簡単な方法で解決したケースがあります。「モディファイドシフトJIS」というコードで、2バイト目が0x5cとなるコードについて、使われていなかった0xfdか0xfeにコードを移動させたのです。このコードについて、どこを探しても資料が見つからないので、記憶にあるだけで詳細はわからないのですが、これだけでエスケープ処理による文字化けも無くせますし、既存のデータを変換するのも、もしかしたらドライバのレイヤで処理できるかもしれない簡易さですし、新しいコードを1から作らなくても解決します。結局、これが広まることは無かったのですがMS-DOSにバックポートされていれば、その後にC言語が多く使われるようになった時に、随分と平穏な世の中になったのではないかとも思います。
UNIXシステムの歴史と最近の動向 石田晴久 情報処理 1986年12月号
実はシフトJISに関しては、他にも対応するJISが旧JISであるか新JISであるか、各社独自で追加した文字コードをシフトJISのどの位置に収めるべきかの混乱がありました。そもそもあくまで特定メーカーのOEMコードであって、なんらオーサライズされたものでもなく、また日本だけではなくアジア圏を含む多くの国に対しても文字コードの拡張が必要なので、AT&Tとしてはそんな訳のわからないコード体系を採用するというわけにはいきませんでした。1985年に日本からの提案でEUCが採用されることとなり、これをもとに国別の機能が定義されJAEとしてEUC-JPが日本語機能に関するものとして実装されるようになりました。これはUNIXのバージョンとは独立に国際化対応として実装されたのですがSVR3あたりから対応が始まりSVR4では標準の機能になっていたように思います。
EUC-JP
しかしながら、¥をパス区切りに採用してしまった(そもそもは他の会社がいけないのだけど)マイクロソフトの罪は深く、その後にパスをネットワークに拡張した際にコンピューター名を表すために¥を重ねて¥¥を使ったために、これをC言語上のリテラルとして表現するには何と¥が4つも必要となる始末でした。だったらC言語が文字エスケープに¥ではなく例えば~を使ってくれたら良かったのにと思わなくもないのですが、この文字も国によっては別の文字が使われていたり、開発当時はそもそもこの文字をキーから打ち込めない端末があったようにも思います。「あまり使われていない」というのは相対的なもので時代によっても変化するものなので仕方がないのですが、エスケープであるとか「メタ」な合図を決めるには多くの配慮が必要なようです。
過去のデータは別として、現役でシフトJISが使われることもほぼ無くなってしまったので(ああ!ExcelのCSV)、この手の問題も忘れ去られることになるのでしょうが、得られた教訓だけは忘れないで欲しいですね。なお、モディファイドシフトJISに関する情報をお持ちの方がいらっしゃいましたら、ぜひともお知らせください。
2024/6/4 追記
ちょっと書き足りなかったので追記・補足します。
もし0x20~0x3fを第2バイトで使っていれば文字列の途中に空白が含まれるので不用意に文字列が区切られてしまったり、「"」によって文字列リテラルが誤認されてしまうでしょう。それが理由でこの範囲を使わなかったのであれば、0x5b~0x5fと0x7b~0x7eも使ってはいけなかったのですよ。逆に0x30~0x39は大丈夫だったのではと思うのですが、おそらく変換規則が複雑になるのを避けたかったのでしょうね。上位4ビットの処理で済ませたかった?(0x7fは例外)
ヘッダ画像は、Copilotの力作です!
#文字コード #日本語文字コード #シフトJIS #モディファイドシフトJIS #0x5c #エスケープ文字 #EUC #パス区切り文字