Javascriptプログラムの短縮

ページ公開後も、1byte でもプログラムの長さが減るように改良を加えた。1年かけて 37byte ほど縮めたが、そろそろ限界だとおもう。

ここまで偏執的に短くする必要があるのか、というと…半分は自分の趣味だ(笑)

しかし、半分は仕事上の必然だった。


これはプログラマの経験則だが、プログラムは、長さに応じた確率によって「バグ」が入り込む余地がある。

ここでの「長さ」は、「面積」と言い換えてもよい。単純にバイト数の大小ではなく、行数も関係する、ということだ。

なぜなら、バグの混入は、エディットの際の「うっかり1文字挿入」などで発生するから。

これらの「うっかり編集」の位置がランダムに発生するとすれば、エディタ上での面積が大きいほど可能性が高まることになる。


コンパイル言語なら、コンパイラがエラーを出してくれる可能性が高い。しかし、今回は Javascript で、ユーザーが操作するまで動作しない、という形でプログラムされている。

万が一うっかり編集でバグが混入すると、混入したことにも気づかず放置される可能性があるのだ。


今回のメールアドレス表記の手法は、クライアントが「スパムボットを除けられる形でメールアドレスを表示したい」と言ったことから考案した。

この仕事では、僕がサイトのプログラム構築を請け負ったが、今後のコンテンツ拡充はクライアント側の役割となる。つまり、メールアドレス表記プログラムは、自分の手を離れて保守されることになる。

商売のチャンスとしてのメール連絡を逃がさない、というのが至上命題で作られたプログラムだ。ここでバグが発生して、「メール連絡お断り」状態にしてはならない。

この必然から、メールアドレス表記部分のプログラムを、少しでも短くする必要があった。




なんの工夫もしないメールアドレス表記の場合、たとえば


<a href="mailto:nobody@example.co.jp">nobody@example.co.jp</a>

と書けば、62byte で済む。アドレスの長さによって異なるが、一般に 60~70byte 程度と思う。これがプログラムの「最小サイズ」だ。スパム除けの機能を入れる場合、この最小サイズに付加される「コスト」がどの程度か、が一つの目安となる。


アドレスや機能が多少違うので一概に比較できないが、同じアドレスを、参考例1では 451byte 14行、参考例2では 436byte 7行、 参考例3では、なんと 1859byte 18行で表現する。

コストとして、プログラム容量が7~30倍、行数が7~18倍になった。


これは「Javascript が動作しない環境」への考慮をしない状態での値なので、考慮が必要ならプログラム容量はさらに増加する。

(参考例1では、Javascript が動作しない環境へのタグ追加を推奨しているが、このタグだけで 63byte ある。)


このページで扱った手法は、nobody@example.co.jp 宛のアドレス表記が 125byte 1行で、Javascript が動作しない環境への配慮も込みだ。

コストが2倍程度なら、「保守のしやすさ」だけに関して言えば及第点だと思う。2倍を切りたかった、というのが本音だが、現状ではこれ以上縮む気がしない。(今後も何か気づいたら改良するけど)




この手のプログラムでは、とにかく文字を「隠す」ために、アスキーコード化するものが多い。

Javascript の String.fromCharCode メソッドでは、アスキーコードを複数個渡し、文字列を得ることができる。だから、アスキーコードから文字列を作るのに、ループをまわす必要すらない。


でも、この方法だと、文字列部分は3倍以上になる。1文字が数字2桁で表されるとして、文字の区切りに , (カンマ)を入れる必要があるので、1文字を3文字に変換する形になるのだ。

自分が「もっと短くできるだろ」と思ったのは、そのようなプログラムを最初に見たからだった。



ちょっと気が利いたプログラムでは、換字式暗号を使うことが多い。

文字列から1文字を取り出し、アスキーコードを得て、数値に演算を施してから、先に書いた String.fromCharCode で文字に戻すのだ。

自分が作ったプログラムも、最初はこの形式だった。コードで3つずらす、いわゆる「シーザー暗号」だった。


Javascript では、「1文字取り出してコード化」ではなく、「文字列の、特定位置の文字をコード化」で表現される。 charCodeAt というメソッドだ。

charCodeAt して、String.fromCharCode することの繰り返し。このメソッドの名前は、規定されたものなのでこれ以上短くできない。プログラム短縮の最大の壁だった。



ふと気づいて、換字式暗号ではなく、転置式暗号に変えてみた。

転置式暗号の解読に必要な処理は、文字を取り出して連結するだけ。取り出しは文字列を「文字配列」とみなす C言語由来の表記により、配列の演算子のみで出来る。連結も + 演算子だけでできる。上述の「名前の長いメソッド」をすべて排除できた。

ただし換字式と違って「文字を取り出す位置」が複雑になる。このため、前処理のプログラムが多少長くなった。


結果としては、32バイトの短縮。短縮する際には「ひらめき」が必要なので3回に分けて短縮したのだが(20,5,7 byte づつ減らした)、結果を見ればなかなかに「劇的な短縮」だと思う。自画自賛だけど。

今後も、なにか思いつけば少しづつ短くする予定だが、そろそろ限界だと考えている。




ちなみに、換字式暗号はシーザー暗号、転置式暗号はスキュタレー暗号として知られている。
どちらも紀元前から存在する暗号で、簡単に解読できる。
今回の目的は「解読されない暗号を作ること」ではなく、「人には簡単に解読されるが、ロボットを欺くには十分なものを作る」ことなので、これで十分。

おまけ

実際の稼動ページは、Javascript プログラムから、コメントやスペースや改行を抜いて短くしてある。

これでは、参考にするにも読みにくいと思うので、下に元のプログラムを公開する。(jQuery使用)

…もっとも、最初から短くする気で書いたので、読みやすいわけではない。

(ページ作成 2012-01-30)
(最終更新 2012-09-17)

前記事:Javascript で canvasへ文字を描く     戻る
トップページへ

-- share --

0000

-- follow --




- Reverse Link -