生成所有可能的n字符密码

时间:2014-03-30 01:10:49

标签: go

作为Learning-Go练习的一部分,我正在编写一个简单的暴力密码破解程序。

要生成在Python中使用字符A-E的所有可能的双字符密码,我会使用itertools.product()

from itertools import product
for permutation in product('ABCDE', repeat=2):
  print permutation

但是,我在Go中努力做到这一点。

Other questions似乎与排列有关,这不是我想要的 。虽然Python文档包含该函数的示例实现,但我不知道如何将yield翻译成Go。

我想我应该提到两个限制:

  1. 我希望密码的长度可变。也就是说,我可能想要使用8个字符的密码,或者6个字符或其他东西。这意味着我们不能只嵌套n个循环。
  2. 我不想立刻把所有这些都记在内存中。

2 个答案:

答案 0 :(得分:10)

你想要的基本上是一组自己的n-ary cartesian product。因此,对于所有3个字符的密码,您需要Prod(设置,设置,设置)。这可以迭代构造。首先构造n-1产品,然后为每个产品和初始集合的每个元素添加元素。例如,所有2个字符的密码 - > 3个字符的密码,其中唯一有效的字符是'a'或'b'。

"ab" = {a,b} - > {(a,a),(a,b),(b,a),(b,b)} - > {(a,a,a),(a,a,b),(a,b,a),(a,b,b),(b,a,a),(b,a,b),(b,b,a),(b,b,b)}

func NAryProduct(input string, n int) []string {
    if n <= 0 {
        return nil
    }

    // Copy input into initial product set -- a set of
    // one character sets
    prod := make([]string, len(input))
    for i, char := range input {
        prod[i] = string(char)
    }

    for i := 1; i < n; i++ {
        // The bigger product should be the size of the input times the size of
        // the n-1 size product
        next := make([]string, 0, len(input)*len(prod))

        // Add each char to each word and add it to the new set
        for _, word := range prod {
            for _, char := range input {
                next = append(next, word + string(char))
            }
        }

        prod = next
    }

    return prod
}

游乐场版:http://play.golang.org/p/6LhApeJ1bv

应该注意的是,这个解决方案还有很大的改进空间。如果要构造长度的所有密码,例如6-18,则为每个密码单独调用此方法将重新计算先前计算的集合。我会留下更好的版本给你。鉴于我向您展示的内容,修改代码以获取任意(n-m)ary产品并从中计算n-ary产品应该不会太困难。 (提示:考虑如何递归地执行此操作)

答案 1 :(得分:7)

例如,满足您的限制,

package main

import "fmt"

func nextPassword(n int, c string) func() string {
    r := []rune(c)
    p := make([]rune, n)
    x := make([]int, len(p))
    return func() string {
        p := p[:len(x)]
        for i, xi := range x {
            p[i] = r[xi]
        }
        for i := len(x) - 1; i >= 0; i-- {
            x[i]++
            if x[i] < len(r) {
                break
            }
            x[i] = 0
            if i <= 0 {
                x = x[0:0]
                break
            }
        }
        return string(p)
    }
}

func main() {
    np := nextPassword(2, "ABCDE")
    for {
        pwd := np()
        if len(pwd) == 0 {
            break
        }
        fmt.Println(pwd)
    }
}

输出:

AA
AB
AC
AD
AE
BA
BB
BC
BD
BE
CA
CB
CC
CD
CE
DA
DB
DC
DD
DE
EA
EB
EC
ED
EE