![](/img/trans.png)
[英]Generate all possible combinations from given characters and length (wordlist)
[英]Generate all possible string from a given length
我希望能夠從給定的長度生成所有可能的字符串,坦率地說,我不知道如何編寫代碼。 因此,為了進一步解釋,我和一位朋友想展示一些基本的黑客攻擊技術,因此會出現強制攻擊。 當然,他將是我的受害者,那里沒有違法的東西。
然而,他告訴我的唯一一件事是他的PW將是4個字符長,但我很確定他的PW不會出現在任何字典中,這很容易。
所以我提出了生成每個4-char-long-string的想法,包含az字符(無上限)。
是否有人可以跟隨代碼編寫這樣的算法? 我真的不打擾表演,如果需要1晚才能生成所有PW,那沒問題。
別忘了,這只是出於演示目的。
您可以通過數字來完成它。 從aaaa開始。 然后增加“最不重要”的部分,所以aaab。 繼續前進,直到你到達aaaz。 然后增加到aaba。 重復,直到你到達zzzz。
所以你需要做的就是實現
String getNext(String current)
為了擴展這個; 它可能不是最快捷的做事方式,但它是最簡單的做法。
正如古老的諺語所說的那樣 - “首先使它成為正確的,然后讓它快速”。 獲得通過所有測試的工作實現(你確實有測試,對嗎?)就是你先做的。 然后你重寫它以使其快速,使用你的測試作為保證你沒有打破核心功能。
絕對最簡單的方法是使用四個嵌套循環:
char[] pw = new char[4];
for (pw[0] = 'a' ; pw[0] <= 'z' ; pw[0]++)
for (pw[1] = 'a' ; pw[1] <= 'z' ; pw[1]++)
for (pw[2] = 'a' ; pw[2] <= 'z' ; pw[2]++)
for (pw[3] = 'a' ; pw[3] <= 'z' ; pw[3]++)
System.out.println(new String(pw));
這不能很好地擴展,因為添加額外的字符需要添加嵌套級別。 遞歸方法更靈活,但更難理解:
void findPwd(char[] pw, int pos) {
if (pos < 0) {
System.out.println(new String(pwd));
return;
}
for (pw[pos] = 'a' ; pw[pos] <= 'z' ; pw[pos]++)
findPwd(pw, pos-1);
}
調用這樣的遞歸方法:
char[] pw = new char[4];
findPwd(pw, 3);
private static void printAllStringsOfLength(int len) {
char[] guess = new char[len];
Arrays.fill(guess, 'a');
do {
System.out.println("Current guess: " + new String(guess));
int incrementIndex = guess.length - 1;
while (incrementIndex >= 0) {
guess[incrementIndex]++;
if (guess[incrementIndex] > 'z') {
if (incrementIndex > 0) {
guess[incrementIndex] = 'a';
}
incrementIndex--;
}
else {
break;
}
}
} while (guess[0] <= 'z');
}
public class GenerateCombinations {
public static void main(String[] args) {
List<Character> characters = new ArrayList<Character>();
for (char c = 'a'; c <= 'z'; c++) {
characters.add(c);
}
List<String> allStrings = new ArrayList<String>();
for (Character c : characters) {
for (Character d : characters) {
for (Character e : characters) {
for (Character f : characters) {
String s = "" + c + d + e + f;
allStrings.add(s);
}
}
}
}
System.out.println(allStrings.size()); // 456 976 combinations
}
}
這是你可以遞歸做的事情。
讓每個(n)
字符密碼定義所有(n-1)
字符密碼的集合,以每個字母a
到z
為前綴。 所以(n)
字符密碼的數量是(n-1)
字符密碼的26倍。 請記住,這是針對由小寫字母組成的密碼。 顯然,你可以很容易地增加每個字母的范圍。
既然您已經定義了遞歸關系,那么您只需要終止條件。
那就是只有一個 (0)
字符密碼,即空字符串。
所以這是遞歸函數:
def printNCharacterPasswords (prefix, num):
if num == 0:
print prefix
return
foreach letter in 'a'..'z':
printNCharacterPasswords (prefix + letter, num - 1)
被稱為:
printNCharacterPasswords ("", 4)
而且,由於Python是一種非常棒的偽代碼語言,你可以只用前五個字母來看它:
def printNCharacterPasswords (prefix, num):
if num == 0:
print prefix
return
for letter in ('a', 'b', 'c', 'd', 'e'):
printNCharacterPasswords (prefix + letter, num - 1)
printNCharacterPasswords ("", 2)
哪個輸出:
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
Aroth指出,使用數字計數器方法更快。 為了使速度更快,您可以使用最后一位數字的內循環和其余數字的計數器組合(因此數字位數可以變化)
public static void main(String... args) {
long start = System.nanoTime();
int letters = 26;
int count = 6;
final int combinations = (int) Math.pow(letters, count);
char[] chars = new char[count];
Arrays.fill(chars, 'a');
final int last = count - 1;
OUTER:
while (true) {
for (chars[last] = 'a'; chars[last] <= 'z'; chars[last]+=2) {
newComination(chars);
chars[last]++;
newComination(chars);
}
UPDATED:
{
for (int i = last - 1; i >= 0; i--) {
if (chars[i]++ >= 'z')
chars[i] = 'a';
else
break UPDATED;
}
// overflow;
break OUTER;
}
}
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d combinations%n", time / 1e9, combinations);
}
private static void newComination(char[] chars) {
}
版畫
Took 0.115 seconds to generate 308,915,776 combinations
注意:循環非常簡單,很可能JIT可以消除關鍵代碼片段(在內聯newCombination之后),並且它如此快速的原因是它沒有真正計算每個組合。
一種生成組合的簡單方法。
long start = System.nanoTime();
int letters = 26;
int count = 6;
final int combinations = (int) Math.pow(letters, count);
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < combinations; i++) {
sb.setLength(0);
for (int j = 0, i2 = i; j < count; j++, i2 /= letters)
sb.insert(0, (char) ('a' + i2 % letters));
// System.out.println(sb);
}
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d combinations%n", time / 1e9, combinations);
版畫
aaaa
aaab
aaac
....
zzzx
zzzy
zzzz
Took 0.785 seconds to generate 456,976 combinations
它花費大部分時間等待屏幕更新。 ;)
如果您注釋掉打印組合的行,並將計數增加到5和6
Took 0.671 seconds to generate 11,881,376 combinations
Took 15.653 seconds to generate 308,915,776 combinations
public class AnagramEngine {
private static int[] anagramIndex;
public AnagramEngine(String str) {
AnagramEngine.generate(str);
}
private static void generate(String str) {
java.util.Map<Integer, Character> anagram = new java.util.HashMap<Integer, Character>();
for(int i = 0; i < str.length(); i++) {
anagram.put((i+1), str.charAt(i));
}
anagramIndex = new int[size(str.length())];
StringBuffer rev = new StringBuffer(AnagramEngine.start(str)+"").reverse();
int end = Integer.parseInt(rev.toString());
for(int i = AnagramEngine.start(str), index = 0; i <= end; i++){
if(AnagramEngine.isOrder(i))
anagramIndex[index++] = i;
}
for(int i = 0; i < anagramIndex.length; i++) {
StringBuffer toGet = new StringBuffer(anagramIndex[i] + "");
for(int j = 0; j < str.length(); j++) {
System.out.print(anagram.get(Integer.parseInt(Character.toString(toGet.charAt(j)))));
}
System.out.print("\n");
}
System.out.print(size(str.length()) + " iterations");
}
private static boolean isOrder(int num) {
java.util.Vector<Integer> list = new java.util.Vector<Integer>();
String str = Integer.toString(num);
char[] digits = str.toCharArray();
for(char vecDigits : digits)
list.add(Integer.parseInt(Character.toString(vecDigits)));
int[] nums = new int[str.length()];
for(int i = 0; i < nums.length; i++)
nums[i] = i+1;
for(int i = 0; i < nums.length; i++) {
if(!list.contains(nums[i]))
return false;
}
return true;
}
private static int start(String str) {
StringBuffer num = new StringBuffer("");
for(int i = 1; i <= str.length(); i++)
num.append(Integer.toString(i));
return Integer.parseInt(num.toString());
}
private static int size(int num) {
int size;
if(num == 1) {
return 1;
}
else {
size = num * size(num - 1);
}
return size;
}
public static void main(final String[] args) {
final java.util.Scanner sc = new java.util.Scanner(System.in);
System.out.printf("\n%s\t", "Entered word:");
String word = sc.nextLine();
System.out.printf("\n");
new AnagramEngine(word);
}
}
將您希望密碼包含的所有字符放入數組中。 編寫一個存根函數來測試您的算法是否找到了正確的密碼。 從長度為1的密碼開始,最多運行4次,看看每次迭代是否找到了您的假密碼。
您可以使用以下代碼獲取隨機字符串。 它會返回一串32個字符。 你可以使用substring()獲得所需長度的字符串。 就像你想要一個包含10個字符的字符串一樣:
import java.security.SecureRandom;
import java.math.BigInteger;
SecureRandom srandom = new SecureRandom();
String rand = new BigInteger(176, srandom).toString(32);
rand.substring(0,7);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.