JavaScriptで文字列の総当たり処理
JavaScriptでExcelの列名のような a, b, c, ・・・, z, aa, ab, ac, ・・・
と無限に増えていく文字列を生成する処理を考えてみる。
まず最初に思いついたのが普通に文字列をインクリメントしながら、最後の文字になったら1桁増やすというやり方。コードは以下のとおり。
String.prototype.succ = function() { return String.fromCharCode(this.charCodeAt(this.length-1) + 1) }; var ALPHA = []; for(var c = "a"; c <= "z"; c = c.succ()) ALPHA.push(c); // ここまではアルファベットの配列を作る処理 var next = (function(ary) { return function(c) { var low = c.slice(-1); var high = c.slice(0, -1); if(ary.indexOf(low) == ary.length - 1) { return (high ? next(high) : ary[0]) + ary[0]; } else { return low ? high + low.succ() : "" } } })(ALPHA); for(var i = 0, c = "a"; i < 10000; i++) { console.log(c); c = next(c); }
next関数に a を渡したら b が返り, z を渡したら aa が返ってくる。
他に思いついたやり方としては文字セット同士の直積を取るやり方。
['a', 'b', 'c']と['a', 'b', 'c']の直積は["aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc"]となるので、最終的な文字の長さ分['a', 'b', 'c']をかければ良い。
以前作った関数を利用する。こちらの方がコードは綺麗かも。但し一文字単位で扱えない。
var ary = ALPHA; for(var i = 0, tmp = ALPHA; i < 3; i++) { for(var j = 0; j < ary.length; j++) { console.log(flatten(ary[j]).join("")); } ary = product(ary, ALPHA); }
こんなコードを作って何がやりたかったかというと、別にパスワードのクラッキングをやりたかったわけではない。
JavaScriptで無限に再帰呼び出しを続けているとある程度再帰したところでtoo much recusionというエラーが出る。
おそらく処理系が再帰の深さをカウントしてエラーを出してるのだと思うけど、動的に関数を定義しながら別の関数を呼び出し続けたらエラーが出ずにずっと呼び出し続けるのかが知りたくて、定義した関数の名前を付ける為の処理として書いた。
しかしよく考えたら関数を呼び出すのに名前を付ける必要なんてなく匿名で問題なかった。まぁどこかで使う事もあるだろう。パスワードクラックとか。。。
ちなみに本来の目的の方は、再帰にならないように動的に関数を定義して呼び出すコードの書き方が思いつかず実験は未完。