在下面的代码中,我试图通过所有可能的字母组合来表示运行时变量的字符数。
这段代码的目的是构建一种密码破解器,它基本上是强力猜测字符串。我想使用循环,因为一旦正确的组合被击中,我将能够打破循环,从而节省了时间和资源,否则在我尝试在第一步中构建所有可能组合的数组时将需要这些。 / p>
我有一个静态代码,适用于5个字符长的字符串,但实际上我的字符串可以是任意长度。如何使我的代码可以使用任何长度的字符串?
let len = textField.text?.characters.count //Length of string
let charRange = "abcdefghijklmnopqrstuvwxyz" //Allowed characterset
for char1 in charRange.characters {
for char2 in charRange.characters {
for char3 in charRange.characters {
for char4 in charRange.characters {
for char5 in charRange.characters {
// Do whatever with all possible combinations
}
}
}
}
}
我想我必须以某种方式利用for totalChars in 1...len {
,但无法弄清楚如何动态创建for循环?
答案 0 :(得分:1)
根据 Martin R 的建议,您可以使用递归
func visit(alphabet:[Character], combination:[Character], inout combinations:[String], length: Int) {
guard length > 0 else {
combinations.append(String(combination))
return
}
alphabet.forEach {
visit(alphabet, combination: combination + [$0], combinations: &combinations, length: length - 1)
}
}
func combinations(alphabet: String, length: Int) -> [String] {
var combinations = [String]()
visit([Character](alphabet.characters), combination: [Character](), combinations: &combinations, length: length)
return combinations
}
现在,如果你想要3个字符的每个组合,并且你想要"ab"
作为字母表,那么
combinations("ab", length: 3) // ["aaa", "aab", "aba", "abb", "baa", "bab", "bba", "bbb"]
请注意,如果您在字母表中插入重复项,则会在结果中显示重复的元素。
将visit
函数作为节点多次调用到高度为k-ary
的完美h
树中,其中:
k
:alphabet
param h
:length
param 这样的树有
节点。这是调用函数的确切次数。
理论上 执行访问的同时分配的最大堆栈帧数为length
。
然而,由于Swift编译器确实实现了Tail Call Optimization,所分配的堆栈帧数仅为1.
最后,我们必须考虑combinations
与结果数量一样大:alphabet^length
因此,时间复杂度是length
和elements into the result
的最大值。
它是O(length + alphabet^length)
事实证明你想要一个暴力密码破解者。
func find(alphabet:[Character], combination:[Character] = [Character](), length: Int, check: (keyword:String) -> Bool) -> String? {
guard length > 0 else {
let keyword = String(combination)
return check(keyword: keyword) ? keyword : nil
}
for char in alphabet {
if let keyword = find(alphabet, combination: combination + [char], length: length - 1, check: check) {
return keyword
}
}
return nil
}
最后一个参数check
是一个闭包,用于验证当前单词是否是正确的密码。您将把逻辑放在此处,一旦找到密码,find
就会停止。
实施例
find([Character]("tabcdefghil".characters), length: 3) { (keyword) -> Bool in
return keyword == "cat" // write your code to verify the password here
}
答案 1 :(得分:1)
想法:使用字母表中的索引数组形成字符串;每次增加指数。
[0, 0, 0] -> [1, 0, 0] -> [2, 0, 0] ->
[0, 1, 0] -> [1, 1, 0] -> [2, 1, 0] ->
[0, 2, 0] -> [1, 2, 0] -> [2, 2, 0] ->
[0, 0, 1] ... [2, 2, 2]
这是一个使用长度为3且字母为abcd
let len = 3
let alphabet = "abcd".characters.map({ String($0) })
var allStrings = [String]()
let maxIndex = alphabet.endIndex
var indicies = Array(count: len, repeatedValue: 0)
outerLoop: while (true) {
// Generate string from indicies
var string = ""
for i in indicies {
let letter = alphabet[i]
string += letter
}
allStrings.append(string)
print("Adding \(string)")
// Increment the index
indicies[0] += 1
var idx = 0
// If idx overflows then (idx) = 0 and (idx + 1) += 1 and try next
while (indicies[idx] == maxIndex) {
// Reset current
indicies[idx] = 0
// Increment next (as long as we haven't hit the end done)
idx += 1
if (idx >= alphabet.endIndex - 1) {
print("Breaking outer loop")
break outerLoop
}
indicies[idx] += 1
}
}
print("All Strings: \(allStrings)")
答案 2 :(得分:1)
递归的替代方法是循环使用字母表的数字表示,使用代表不同数量字母的基数代表。这种方法的一个限制是echo "$GREEN$(ifconfig en0 | awk '/inet / {print $2}')$NC"
初始化程序最多允许base36数(基数36),即,你最多可以执行你的密码破解"使用一组具有唯一计数< = 36的字符。
帮助功能
String(_:,radix:)
主要基数暴力密码检查方法
// help function to use to pad incremental alphabeth cycling to e.g. "aa..."
let padToTemplate: (str: String, withTemplate: String) -> String = {
return $0.characters.count < $1.characters.count
? String($1.characters.suffixFrom($0.characters.endIndex)) + $0
: $0
}
示例用法#1
// attempt brute-force attempts to crack isCorrectPassword closure
// for a given alphabet, suspected word length and for a maximum number of
// attempts, optionally with a set starting point
func bruteForce(isCorrectPassword: (String) -> Bool, forAlphabet alphabet: [Character], forWordLength wordLength: Int, forNumberOfAttempts numAttempts: Int, startingFrom start: Int = 0) -> (Int, String?) {
// remove duplicate characters (but preserve order)
var exists: [Character:Bool] = [:]
let uniqueAlphabet = Array(alphabet.filter { return exists.updateValue(true, forKey: $0) == nil })
// limitation: allows at most base36 radix
guard case let radix = uniqueAlphabet.count
where radix < 37 else {
return (-1, nil)
}
// begin brute-force attempts
for i in start..<start+numAttempts {
let baseStr = String(i, radix: radix).characters
.flatMap { Int(String($0), radix: radix) }
.map { String(uniqueAlphabet[$0]) }
.joinWithSeparator("")
// construct attempt of correct length
let attempt = padToTemplate(str: baseStr,
withTemplate: String(count: wordLength, repeatedValue: alphabet.first!))
// log
//print(i, attempt)
// test attempt
if isCorrectPassword(attempt) { return (i, attempt) }
}
return (start+numAttempts, nil) // next to test
}
示例用法#2(选择一个失败&#34;批次&#34;另一个)
// unknown content closure
let someHashBashing : (String) -> Bool = {
return $0 == "ask"
}
// setup alphabet
let alphabet = [Character]("abcdefghijklmnopqrstuvwxyz".characters)
// any success for 500 attempts?
if case (let i, .Some(let password)) =
bruteForce(someHashBashing, forAlphabet: alphabet,
forWordLength: 3, forNumberOfAttempts: 500) {
print("Password cracked: \(password) (attempt \(i))")
} /* Password cracked: ask (attempt 478) */