文字の全ての組み合わせの列挙

例えばパスワードに総当たり攻撃をかけるときには、文字のあらゆる組み合わせからなるパスワードを作ってみて攻撃することになります。どういうアルゴリズムで作れるのか興味を持ったので書いてみました。


こんなクラスを定義しておきます。いまいちスマートじゃない気がしますが。

class Query {
    private const string LETTERS = "abcdefghijklmnopqrstuvwxyz";
    private List<int> data;
    /// <summary>
    /// 初期化
    /// </summary>
    public Query() {
        data = new List<int>();
        data.Add(0);
    }
    /// <summary>
    /// クエリの長さ
    /// </summary>
    public int Length { get { return data.Count; } }
    /// <summary>
    /// 次のクエリを作る
    /// </summary>
    public void Next(){
        Advance(0);
    }
    /// <summary>
    /// 繰り上がり
    /// </summary>  
    /// <param name="figure">繰り上がりを判定する桁</param>
    private void Advance(int figure) {
        if (data.Count <= figure) {
            data.Add(0);
        }
        else if (data[figure] >= LETTERS.Length - 1) {
            Advance(figure + 1);
            data[figure] = 0;
        }
        else {
            data[figure] += 1;
        }
    }
    /// <summary>
    /// 文字列形式を返す
    /// </summary>
    public override string ToString() {
        char[] str = new char[data.Count];
        for (int i = 0; i < data.Count; i++) {
            str[data.Count - i - 1] = LETTERS[data[i]];
        }
        return new string(str);
    }
}

このQueryクラスを使って、こんな風に書くとa-z,aa-zz,aaa-zzzの文字列が表示されます。

for (Query query = new Query(); query.Length <= 3; query.Next() ) {
    Console.WriteLine(query.ToString());
}