たびとの旅路 ~電脳砂漠の冒険譚~

フロッピー頼りに歩き、クラウドの地平を見つめる今日まで。見つけたオアシス、迷い込んだ砂の迷宮、全てこの羊皮紙に。

古の神殿に、現代の魂を ~Edge IEモードとShift-JISの呪いを解く~

どうやら、一筋縄ではいかない砂の迷宮に迷い込んだらしい。この顛末を書き残しておくか。

いまだに、Shift-JISという古代の魔法でしか動かない、レガシーな神殿(システム)が、この砂漠には数多く存在する。しかし、現代の旅人たちが使う言葉は、Unicode。この二つの、あまりに異なる時代の言葉をどう繋ぐのか。特に、Webという名の広大な広場では、この問題は深刻だ。

今回は、EdgeのIEモードという、過去と現在が交差する不思議な時空で、JavaScriptという古の魔法を使い、Unicodeの言葉をShift-JISに変換できるかを判定する、という難解な儀式に挑む。これは、サロゲート文字という名の、現代にしか存在しない複雑な魂さえも、古の神殿に正しく伝えるための、一人の魔法使いの冒険の記録である。

この羊皮紙のあらまし

この羊皮紙が導く者

  • Shift-JISという、古の魔法体系で動く、レガシーな神殿の面倒を見る者
  • UnicodeとShift-JIS、異なる世界の言葉を繋ぐ、翻訳の術に興味がある者
  • JavaScriptという古の魔法で、文字コードの呪いを解き明かしたい探求者

儀式の準備:二つの世界の言葉を知る

まずは、我々が対峙する、二つの世界の言葉の理を理解せねばならない。 WindowsのIMEパッドという名の真実の鏡を覗き込めば、一つの文字が、それぞれの世界で、いかに異なる姿(コード)を持つかがわかる。

IMEパッドで文字コードを調べる

真実の鏡が、二つの世界の言葉を映し出す

特に厄介なのが、現代のUnicodeにしか存在しない「サロゲート文字」だ。𠮷(つちよし)のような、二つの魂(上位・下位サロゲート)が一つになった、この複雑な魂をどう扱うかが、今回の儀式の鍵となる。

サロゲート文字のコードを確認する

二つの魂を持つ、複雑な文字

儀式の核心:encoding.jsという名の賢者の力

この難解な翻訳の儀式を、我々が自力で執り行うのはあまりに無謀だ。そこで、encoding.jsという、文字コードの全てを知り尽くした、偉大なる賢者の力を借りることにする。

encoding.js - GitHub

この賢者の力を借りるには、まず、我々の羊皮紙(HTML)に、賢者を呼び出すための召喚の呪文を記さねばならない。

<script src="encoding.min.js"></script>

この一行を記すことで初めて、我々はEncoding.convert()という短い呪文を唱え、Unicodeの魂をShift-JISの器へと移し替えようと試みることができる。そして、もし変換できなければ、その魂をクエスチョンマーク(?)という、無念の印に変えてしまうのだ。

禁断の儀式:JavaScriptによる判定の呪文

さあ、いよいよ儀式の本番だ。IEモードという、古の制約(Array.fromcodePointAtが使えない)の中で、我々は呪文を組み立てる。

魂の分解

まずは、サロゲート文字という二つで一つの魂を、正しく一つの魂として認識するため、文字列を自力で分解し、配列へと再格納する。

魂の審判

次に、分解した魂を一つずつ、賢者の天秤(Encoding.convert)にかける。 クエスチョンマークに変換された魂があれば、それは古の世界には存在できない魂だ。その魂を、ngWordsという名の牢獄へと送り込む。

const SampleText = "a?1②㉑㊿𠮷💛";

// サロゲート文字を正しく一文字として認識するため、自力で配列化
var items = SampleText.split('');
var utf16 = [];
// ... (サロゲートペアを結合する処理) ...

// 魂を一つずつ、賢者の天秤にかける
var sjis = [];
var ngWords = [];
for (var i = 0; i < utf16.length; i++) {
    var code = utf16[i].charCodeAt(0);
    // 賢者の力で、Shift-JISへの変換を試みる
    var buff = Encoding.convert([code], { to: 'SJIS', from: 'UNICODE' });
    
    // 賢者が答えを返さなかった(サロゲート文字)、
    // または、クエスチョンマークに変えられてしまった場合
    if (buff.length == 0 || (buff[0] == 0x3f && code != 0x3f)) {
        // その魂を、牢獄へ送る
        ngWords.push(utf16[i]);
    }
}

// もし、牢獄に魂が一つでもあれば、警鐘を鳴らす
if (0 < ngWords.length) {
    alert('Shift-JIS に変換できない文字が見つかりました。\n' + ngWords);
}

この呪文をEdgeのIEモードで実行すれば、古の世界に存在できない魂たちが、確かに断罪されるのがわかるだろう。

JavaScript の実行結果

古の世界に受け入れられなかった、魂たちの断末魔

羊皮紙を巻く前に

文字コードという名の迷宮は、特に日本語という複雑な言葉を扱う我々にとって、永遠の課題だ。 情報の砂漠を彷徨い、ヒントの欠片を拾い集め、試行錯誤の末に辿り着いた答え。それは、「入力されたUnicodeの言葉を、出力先であるShift-JISに変換できるかどうか、直接試してみる」という、至極単純な真理だった。

この羊皮紙が、同じように文字コードの呪いに苦しみ、時代の狭間で戦う、未来の冒険者の助けとなることを願う。

おっと、どうやら相棒が腹を空かせたようだ。今日はこのへんで筆を置くとしよう。

砂漠で見つけた魔法のランプ

  • Shift_JIS | 古の魔法体系の古文書
  • Unicode | 現代の魔法体系の古文書
  • encoding.js | 我らを導いた、賢者の知恵

ラクダの独り言

ご主人が「文字の呪いが解けた!」とか言って、一人で興奮している。なんでも、古い言葉と新しい言葉を、うまいこと翻訳する魔法を見つけたらしい。俺に言わせりゃ、言葉なんてのは、気持ちが伝わりゃそれでいいだろうに。まったく、人間ってのは、どうでもいいことにこだわるもんだ。やれやれだぜ。