重畳漢字ROM

いかづちSqueak

2013年10月25日 01:41

ちょっとした機器で漢字を表示したい時、文字のデータをROMに持つことになる。
ROMの容量を抑えたいなら、漢字のレパートリーをJIS第1水準のみに絞ったりするだろう。
その際、使う文字コードが(Shift_)JISならば問題ないのだが、何かの都合でUnicodeを使わざるを得ない場合もある…と思う。
(無いと話が終わってしまうのであることにしていただきたい)
ここで発生する問題が、変換テーブルが巨大になるということである。
UnicodeはJISコードとは無関係に文字が並べられているので、UnicodeでJIS第1水準の文字はバラバラに存在している。
例えばこんなだ。

空白部分を漢字ROMに持つのは無駄なのでROMには詰めて入れるが、そうすると文字コードとの対応を別にテーブルでもっておかなければならない。
これがどれほどのデータ量になるか。
まず漢字ROM本体だが、例えば12×12ドットのフォントを使うとして、JIS第1水準漢字2965文字は2965*12*12/8 = 53370Byte ≒ 53KBとなる。
一方変換テーブルだが、JIS第1水準漢字はUnicodeにU+4E00「一」からU+9F8D「龍」までのおよそ21000文字にわたって分布している。
2965文字を指定するには12bit必要なので、素直に考えれば21000*12/8 = 31500Byte、すなわち32KBと、本体の半分ものデータ量になってしまう。

と、ここまでが前置きで、今回これを解決するアルゴリズムを考案した。タイトルにもあるように、このアルゴリズムは「重畳漢字ROM」と名付けた。
この方式では漢字ROMの容量は少々増えるが(今回のサンプルでは14%増)、変換テーブルの容量を劇的に縮小することができる(32KB→1.3KB)。
仕組みは次のようになっている。
・ROMの番地は12bitある。
・その下位4bitは文字コードの下位4bitと同じである。
・上位8bitは文字コードの上位12bitからテーブルを引いて求める。
つまり文字コードの上位12bitが異なる文字を、番地の上位8bitが同じ箇所に押し込めている事になる。
先に述べたとおりUnicode中のJIS第1水準漢字は飛び飛びに存在しているのでこういうことができるのだ。
図で示すと分かりやすいかもしれない。


ただしこの方式には1つ重大な欠点がある。第1水準外の文字が入力された時でも区別できずに何らかの文字を表示してしまうのだ。
きちんと表示させるためにはデータを事前に調整しなければならず、それならJISに変換すればいいじゃないかということになりかねない。

最後にサンプルを用意した。
テキストボックスに任意の第1水準漢字を入れボタンかEnterを押せば下にその漢字の画像が表示される。わざと第2水準漢字を入れて変な文字が出るのを試すのもよいだろう。
変換テーブルはソースを参照。
コードは単純で、漢字ROM相当の画像ファイルの表示位置をずらして当該文字を出している。
なおこのROMの重畳のパターンは文字の多い順に並べてからナイーブな貪欲法で1つづつ重ねて作ったものである。やりようによってはもっと縮められると思う。



//
var exe13024 = function(){ //
var convTable = [2, 45, 83, 83, 46, 57, 0, 23, 47, 11, 5, 16, 48, 34, 39, 85, 74, 92, 2, 49, 9, 50, 0, 79, 78, 32, 75, 93, 14, 7, 37, 87, 99, 89, 58, 12, 44, 26, 27, 48, 43, 127, 20, 60, 124, 128, 36, 33, 25, 1, 111, 15, 1, 1, 38, 51, 37, 107, 7, 76, 44, 71, 8, 52, 53, 88, 82, 54, 84, 137, 92, 102, 130, 130, 41, 93, 25, 76, 90, 50, 18, 39, 129, 94, 65, 12, 115, 20, 40, 122, 128, 60, 13, 74, 3, 21, 4, 16, 106, 90, 27, 14, 29, 127, 161, 0, 0, 131, 131, 0, 132, 29, 112, 59, 8, 24, 128, 7, 0, 0, 117, 90, 93, 70, 0, 0, 82, 0, 157, 3, 37, 69, 84, 96, 39, 130, 42, 0, 37, 0, 0, 131, 124, 51, 135, 146, 126, 32, 91, 156, 132, 0, 49, 0, 152, 0, 128, 34, 52, 46, 4, 65, 73, 64, 133, 22, 151, 44, 88, 81, 50, 11, 95, 90, 63, 94, 155, 75, 20, 4, 77, 134, 96, 129, 97, 95, 129, 31, 164, 96, 23, 118, 56, 94, 134, 83, 161, 127, 11, 12, 0, 165, 0, 0, 58, 0, 72, 0, 55, 0, 148, 95, 0, 23, 68, 0, 14, 6, 52, 24, 2, 22, 71, 78, 7, 135, 147, 25, 55, 130, 13, 149, 0, 117, 97, 136, 0, 0, 98, 127, 59, 18, 171, 0, 0, 142, 159, 0, 107, 0, 0, 183, 99, 82, 26, 27, 98, 165, 95, 93, 106, 100, 157, 8, 47, 17, 50, 99, 137, 161, 143, 40, 99, 15, 123, 28, 184, 102, 56, 100, 57, 5, 101, 69, 94, 30, 166, 111, 0, 96, 58, 0, 134, 132, 59, 8, 42, 105, 61, 130, 148, 102, 133, 49, 103, 136, 0, 0, 18, 125, 33, 14, 54, 154, 133, 64, 79, 158, 0, 25, 79, 60, 131, 100, 72, 112, 21, 38, 26, 32, 197, 54, 116, 28, 104, 100, 138, 139, 125, 138, 86, 131, 109, 103, 48, 92, 9, 108, 162, 105, 162, 104, 89, 0, 154, 117, 41, 111, 176, 89, 106, 134, 98, 135, 15, 0, 133, 34, 0, 0, 45, 51, 85, 140, 101, 89, 92, 78, 29, 87, 133, 98, 16, 185, 55, 54, 56, 109, 45, 47, 104, 139, 158, 125, 77, 50, 104, 21, 0, 17, 79, 61, 24, 106, 43, 62, 35, 49, 151, 45, 137, 20, 107, 63, 0, 30, 138, 13, 141, 60, 105, 31, 153, 25, 163, 75, 106, 108, 141, 140, 58, 171, 12, 53, 0, 156, 186, 142, 109, 103, 143, 9, 0, 0, 132, 153, 0, 167, 198, 96, 109, 108, 199, 160, 184, 101, 66, 0, 0, 0, 0, 168, 115, 0, 51, 113, 110, 62, 126, 128, 32, 120, 110, 63, 0, 21, 47, 75, 0, 0, 145, 164, 0, 102, 111, 11, 160, 112, 134, 143, 142, 64, 113, 137, 36, 140, 200, 135, 98, 139, 41, 137, 15, 137, 121, 144, 180, 156, 169, 165, 170, 80, 62, 145, 33, 0, 187, 113, 127, 112, 163, 107, 53, 88, 171, 137, 0, 62, 81, 126, 76, 123, 138, 110, 56, 161, 70, 165, 0, 185, 144, 0, 114, 0, 0, 105, 136, 0, 0, 124, 172, 68, 146, 0, 118, 172, 163, 0, 0, 177, 0, 173, 168, 119, 48, 178, 67, 139, 188, 164, 0, 186, 154, 74, 134, 0, 67, 0, 189, 10, 139, 26, 115, 136, 162, 0, 27, 80, 57, 116, 142, 135, 0, 173, 147, 141, 135, 0, 153, 58, 111, 92, 179, 93, 100, 0, 148, 61, 147, 0, 104, 109, 0, 149, 164, 164, 165, 0, 0, 130, 0, 177, 78, 103, 0, 82, 104, 34, 166, 66, 69, 113, 148, 187, 201, 145, 154, 101, 23, 78, 0, 0, 0, 0, 167, 159, 0, 115, 142, 165, 85, 182, 57, 129, 16, 95, 112, 183, 167, 174, 170, 0, 146, 0, 0, 0, 140, 170, 0, 202, 63, 171, 125, 143, 144, 116, 0, 152, 143, 144, 143, 117, 166, 190, 188, 171, 167, 0, 167, 0, 0, 150, 118, 3, 110, 171, 53, 0, 121, 97, 17, 119, 148, 174, 138, 85, 87, 117, 65, 172, 175, 28, 55, 123, 144, 191, 176, 179, 83, 120, 131, 177, 22, 180, 84, 79, 0, 0, 160, 145, 151, 169, 119, 0, 36, 0, 0, 0, 189, 142, 174, 0, 0, 70, 70, 66, 155, 108, 175, 151, 157, 140, 81, 35, 67, 121, 72, 103, 46, 122, 0, 152, 168, 42, 153, 154, 19, 94, 171, 178, 152, 110, 123, 157, 179, 175, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 155, 120, 156, 0, 149, 180, 172, 158, 179, 146, 77, 147, 0, 149, 0, 94, 147, 83, 124, 145, 68, 124, 35, 120, 174, 144, 31, 192, 0, 150, 123, 136, 203, 80, 184, 157, 143, 169, 126, 172, 67, 151, 141, 69, 176, 114, 172, 0, 154, 164, 204, 162, 86, 85, 152, 86, 97, 190, 113, 180, 146, 117, 5, 40, 0, 180, 0, 124, 205, 191, 158, 111, 168, 173, 122, 0, 181, 175, 106, 181, 116, 159, 206, 123, 0, 147, 154, 192, 165, 0, 176, 160, 166, 141, 125, 173, 161, 0, 103, 169, 36, 0, 176, 0, 158, 182, 174, 0, 181, 0, 132, 118, 207, 183, 193, 161, 114, 0, 121, 182, 153, 116, 161, 138, 0, 0, 184, 162, 138, 170, 182, 0, 0, 194, 0, 0, 0, 185, 0, 0, 0, 0, 153, 122, 148, 73, 186, 140, 208, 161, 121, 149, 194, 114, 175, 122, 0, 0, 0, 171, 0, 174, 87, 162, 177, 173, 0, 162, 6, 0, 86, 108, 163, 59, 0, 84, 29, 126, 105, 107, 125, 88, 52, 155, 158, 81, 6, 156, 178, 186, 0, 170, 163, 149, 174, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 178, 195, 179, 187, 181, 133, 10, 37, 38, 89, 30, 182, 187, 0, 0, 0, 0, 0, 150, 152, 180, 0, 159, 177, 0, 183, 152, 119, 181, 0, 0, 0, 121, 185, 0, 131, 184, 0, 188, 0, 164, 175, 168, 171, 167, 169, 165, 176, 170, 186, 195, 0, 0, 189, 0, 39, 127, 180, 102, 101, 90, 18, 99, 61, 19, 115, 40, 70, 140, 196, 66, 151, 76, 0, 155, 146, 0, 0, 185, 0, 73, 87, 114, 150, 64, 128, 146, 156, 41, 120, 156, 0, 161, 0, 0, 163, 155, 209, 169, 181, 139, 166, 186, 0, 0, 172, 33, 74, 172, 46, 71, 173, 190, 191, 183, 160, 184, 167, 68, 0, 0, 197, 198, 0, 0, 173, 0, 157, 0, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 91, 183, 118, 176, 179, 158, 0, 0, 0, 185, 196, 157, 159, 192, 71, 42, 72, 65, 141, 159, 43, 193, 43, 82, 168, 171, 183, 178, 0, 129, 160, 162, 172, 164, 150, 0, 0, 178, 136, 158, 73, 44, 173, 160, 91, 88, 184, 0, 0, 0, 168, 0, 0, 194, 177, 80, 169, 155, 172, 0, 0, 185, 0, 0, 0, 174, 175, 10, 91, 151, 0, 187, 157, 166, 174, 178, 0, 197, 0, 0, 0, 0, 177, 178, 165, 180, 77, 0, 0, 0, 0, 186, 153, 182, 189, 0, 159, 179, 119, 0, 188, 195, 181, 164, 187, 180, 178, 196, 182, 24, 0, 0, 0, 0, 0, 0, 0, 0, 175, 19, 170, 210, 162, 211, 0, 187, 145, 0, 190, 0, 0, 166, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 179, 0, 132, 173, 126, 177, 163, 0, 0, 163, 179, 181, 212, 0, 0, 180, 0, 188]; //
var codeorg = "一".charCodeAt(0); //
var ch = document.getElementById("stdin13024").value; //
var code = ch.charCodeAt(0)-codeorg; //
var codel = code%16; //
var codeh = Math.floor(code/16); //
var y = (convTable[codeh])*16; //
var x = codel*16; //
document.getElementById("stdout13024").style.backgroundPosition = "-"+x +"px -"+ y+"px"; //
}; //

関連記事