2023-01-12
問題、ブラウザ上で日本語の文字「福」は何byteで扱われているでしょう?

答、2byte

ES-Jamで確かめてみましょう!
<script type="module"> alert("福".charCodeAt(0)); </script> 31119 とでました。下記の計算の通り、2進法15bitで表現できるので、8bit単位であるbyteでは2byteです。1995年誕生のJavaで文字を表すcharが2byteとなっていた実装は衝撃的でした。JavaScriptを始め多くの言語でその流れを汲んでいます。

Math.log(31119)/Math.log(2) 14.925508080033552

おや、確か3byteだったはず?という方、それはファイルに書き出す時に使用するUTF-8という変換形式の話です。 <script type="module"> alert(new TextEncoder().encode("福")); </script> こちら実行すると「231,166,143」と3byteの結果が表示されます。2byteが基本単位として扱われることが多い文字ですが、数字やよくある記号やアルファベットが多いので、全部を2byteで保存してしまうのはもったいないということで、0から127までは1byte、128から2047までが2byte、2048から65535までが3byte、1114111までが4byteで変換するUTF-8がよく使われています。

8bitのバイナリデータを文字列へと変換するBase122を使ってみましたが、0-127まではUTF-8でも1byteで表現できる有効な文字なので、Base128を作ってみました。


「Base128」

バイナリデータと文字列との相互変換は普通に使えますが、JavaScriptの文字列にしようとすると文字列の始まりの記号、ダブルクォートや、エスケープのための記号、バックスラッシュ、文字列内ではエスケープしないと使えない改行記号(10/13)を変換する encodeJS を使う必要があり、ちょっと容量が増えてしまいます。

改めてBase122の仕組みを読んでみると、上記使えない文字をUTF-8の2byteエンコードを使ってうまく逃がす仕組みになっていました。これだと容量を増やさずに対応できます!スゴイ!ただ、Base122で変換した文字はテキストエディタで表示がおかしくなり、コピペできない文字が含まれてしまっている点が残念です。

そこで、すべての2byteエンコードされる文字を表示してみました。 const n = []; let cnt = 0; for (let i = 0x80; i < 0x800; i++) { if ((i & 0x7f) != 0) { n.push(String.fromCharCode(i)); } else { n.push("\n## " + (i >> 7) + "\n"); } } console.log(n.join(""));


上位4bit毎に16種類ある2byteエンコードの文字たち。エディタVSCodeにコピーしてみて普通に扱えるセットを調べたところ、2/3/4/5/8が普通に読み書きOK、1/7/10は一部フォントがなかったりするけどコピペOKということで、8種類を使うのが良さそうです。Base122は制御コードみたいのが効いてしまう6を使っていることによる問題でした。

何気なく使っている文字にもいろんな秘密やストーリーがあっておもしろいですね。


東京都庁、宮坂副知事に初のリアル対面!
東京都が掲げるデジタル10か条「政策って、デザインだ。」に3つシールを貼りました。

私、一番の推しは「#10 ともに学びつづけよう」、続いて「#7 都政の見える化をしよう」「#2 シンプルなサービスを心がけよう」です。

links
- Base64より効率良いBase122の有効性チェックとbin2js改良によるWASMインポート

Tweet
クリエイティブ・コモンズ・ライセンス
本ブログの記事や写真は「Creative Commons — CC BY 4.0」の下に提供します。記事内で紹介するプログラムや作品は、それぞれに記載されたライセンスを参照ください。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / 「一日一創」画像 / RSS