【问题标题】:brute forcer algorithm with all possible combinations / permutation in a given char array在给定 char 数组中具有所有可能组合/排列的蛮力算法
【发布时间】:2013-09-08 15:40:51
【问题描述】:

对于这件让我烦恼的简单事情需要帮助。 我见过许多类似的算法,但我想完全按照规定的方式做到这一点,以在给定的字符集数组中达到ALL可能的组合/排列。

让我们举一个密码破解暴力破解的例子

例如char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();?

陈述方式:

是这样的。对于当前示例。

a,b,c,d......z     then at last index "z".  

it goes like      

aa,ab,ac....az.        then      

ba,bb,bc,bd........bz          then

same for ca, cb, and so on.

aaaa,aaab,aaac......aaaz   then

baaa,baab,baac.......baaz   to      zzzzzzzzzzzzzzzzzzzzzzzzzz

到目前为止我达到的代码:

(虽然不是一个解决方案)是具有与字符集数组长度一样多的 for 循环。那太疯狂了。这工作正常。但我需要聪明的。

public class Bruteforcer {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
          char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();


         int currentIndex = 0;
         String currentString = "";

         for (int i = 0; i < charset.length; i++) {
            char currentChar = charset[i];

             for (int j = 0; j < charset.length; j++) {

                 char c = charset[j];
                 currentString =  "" +currentChar + c;
                 System.out.println(currentString);

             }


         }


    }
}

【问题讨论】:

  • 您可以使用两个循环来探索所有组合。
  • 是的,但我没有。我确实想通过具体的例子来学习。不过 google 上有很多不同的
  • 那是 javascript 而不是我所说的我想要的方式
  • 你说你想要一个算法......现在你有了它。 SO 不是代码生成器。

标签: java algorithm


【解决方案1】:

要在不递归的情况下解决此问题,保留当前结果的索引数组会有所帮助。这是一个模板类,它将产生您正在寻找的结果:

public abstract class Bruteforce
{
  public void generate( char[] input ) {
    char[] result = new char[input.length];
    int[] index = new int[input.length];

    // initialize the arrays.
    Arrays.fill(result, 0, result.length, input[0]);
    Arrays.fill(index,  0, index.length, 0);

    // loop over the output lengths.
    for( int length = 1; length <= input.length; length++ ) {
      int updateIndex = 0;
      do {
        element(result, 0, length);

        // update values that need to reset.
        for(updateIndex = length-1;
            updateIndex != -1 && ++index[updateIndex] == input.length;
            result[updateIndex] = input[0], index[updateIndex] = 0, updateIndex--);

        // update the character that is not resetting, if valid
        if( updateIndex != -1 ) result[updateIndex] = input[index[updateIndex]];
      }
      while(updateIndex != -1);
    }
  }
  public void generate( String input ) {
    generate(input.toCharArray());
  }
  public abstract void element(char[] result, int offset, int length);
}

然后您可以扩展模板以将每个元素打印到 STDOUT:

new Bruteforce() {
  public void element(char[] result, int offset, int length) {
    System.out.println(new String(result, offset, length));
  }
}.generate("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

注意:此代码假定输入字符串不包含任何重复字符。

【讨论】:

  • 太棒了!!给我几分钟观察
  • 到目前为止完美!!你确定它不会错过给定数组的任何字符可以进行的任何组合/排列吗?
  • 如果输入的字符串不包含重复的字符,那么这段代码将按照指定的顺序生成您要查找的所有元素。
【解决方案2】:

您需要使用递归。算法的复杂度是指数级的。我希望我能理解这个问题。

public class Generator {
    private char[] charset;

    public Generator()
    {
        charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    }


    public void generate(String str, int pos, int length)
    {
        if (length == 0) {
            System.out.println(str);
        } else {
            for (int i = pos; i < charset.length; i++) {
                generate(str + charset[i], i, length - 1);
            }
        }
    }

    public static void main(String[] args)
    {
        Generator test = new Generator();
        //test.generate("", 1);
        for (int length = 1;  length < 5; length++) // Change 5 with the length of charset
            test.generate("", 0, length);
    }

}

【讨论】:

  • 太棒了!但正如您在输出中看到的那样。 CC 在 BZ 之后,BB 在 AZ 之后。所以BA和CA,CB都被错过了。并且它不在“规定的方式”中。看到最后的输出是 WZZZ XXXX XXXY XXXZ XXYY XXYZ XXZZ XYYY XYYZ XYZZ XZZZ YYYY YYYZ YYZZ YZZZ ZZZZ
  • 嗯。然后我不明白问题所在。为什么不引用原始问题?也许问题是您的解释。
  • 真的很喜欢你的回答和方法,但是。让我们以密码破解器为例。现在BA != AB。所以BA 被错过了。见“规定的方式”
【解决方案3】:
public class Generator {

    private char[] charset;

    private int min; //var added for min char length
    private int max; //var added for max char length

    public Generator() {
        charset = "abcdefghijklmnopqrstuvwxyzAEIOU0123456789!@#$%^&*()-_+=~`[]{}|:;<>,.?/BCDFGHJKLMNPQRSTVWXYZ".toCharArray();
        min = 2; //char min start
        max = 5; //char max end 
    }

    public void generate(String str, int pos, int length) {
        if (length == 0) {
            System.out.println(str);
        } else {

            //This if statement resets the char position back to the very first character in the character set ('a'), which makes this a complete solution to an all combinations bruteforce! 
            if (pos != 0) {
                pos = 0;
            }

            for (int i = pos; i < charset.length; i++) {
                generate(str + charset[i], i, length - 1);
            }
        }
    }

    public static void main(String[] args) {
        Generator bruteforce = new Generator();

        for (int length = bruteforce.min; length < bruteforce.max; length++) // Change bruteforce.min and bruteforce.max for number of characters to bruteforce. 
            bruteforce.generate("", 0, length); //prepend_string, pos, length 
    }
}

我已经修改了上面 rendon 的示例-https://stackoverflow.com/revisions/18685721/1 注意:它允许所有组合,并添加了 min 和 max 变量

【讨论】:

    【解决方案4】:

    您可以使用 recusion 和几个循环。

    public static void printCombinations(int length) {
        printCombinations(new char[length], 0, 0);
    }
    
    private static void printCombinations(char[] chars, int idx, int mask) {
        if (idx == chars.length) {
            System.out.println(chars);
            return;
        }
        for (int i = 0; i < 26; i++) {
            int mask2 = 1 << i;
            if ((mask2 & mask) == 0) {
                chars[idx] = (char) ('A' + i);
                printCombinations(chars, idx + 1, mask | mask2);
            }
        }
    }
    
    public static void main(String[] args) throws Exception {
        for (int i = 1; i <= 3; i++)
            printCombinations(i);
    }
    

    打印

    A
    B
    ...
    ZYWX ... DCBA
    

    一个组合没有重复的字符,所以它不会是 ZZZZZ...

    【讨论】:

    • 暴力破解密码可以是zzzzzzzzz。相同字符的组合也是如此......就像在aa,ab,ac ....az中一样。 “啊”
    • @MasoodAhmad 在这种情况下,解决方案要简单得多。您无需检查重复项。我相信您可以修改代码以删除它;)
    • 哦,好吧..但它不是预定义的数组字符集。因为我可能想包括 abcdefghi 或包括 `` %^^&**((@$# `` 特殊字符。或排除任何字符。
    • 是的,OP 没有意识到关键是理解答案并根据需要应用它们......从概念上讲。不要将 SO 用作从属代码编写器。 +1
    • @MasoodAhmad 在这种情况下,您需要修改代码以允许更多字符。如果您不是开发人员,我建议您聘请一位开发人员。 ;)
    【解决方案5】:

    更面向对象的解决方案

    使用已知长度

    final String target = "ABC";
    final char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    BruteForce.bruteForce(charset, 5, string -> {
        System.out.println(string);
        return string.equals(target);
    });
    

    使用未知长度

    final String target = "ABC";
    final char[] charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    
    // Use your looping method of choice
    boolean found = false;
    int length = 1;
    while (!found) {
        found = BruteForce.bruteForce(charset, length, string -> {
            System.out.println(string);
            return string.equals(target);
        });
        length++;
    }
    

    实施

    public class BruteForce {
    
        public static boolean bruteForce(@NonNull final char[] input, final int length, @NonNull final Closure closure) {
            final char[] chars = new char[length];
            final IncrementalCharSequence incrementalCharSequence = new IncrementalCharSequence(input, chars);
    
            // Use your looping method of choice
            do {
                if (closure.compare(new String(chars))) {
                    return true;
                }
            } while (incrementalCharSequence.increment());
            return false;
        }
    }
    
    public interface Closure {
    
        boolean compare(@NonNull final String string);
    }
    
    public class IncrementalCharSequence {
    
        @NonNull
        private final char[] input;
    
        @Nullable
        private final IncrementalCharSequence subIncrementalCharSequence;
    
        @NonNull
        private final char[] chars;
    
        private final int index;
    
        private int currentIndex;
    
        public IncrementalCharSequence(@NonNull final char[] input, @NonNull final char[] chars) {
            this(input, chars, 0);
        }
    
        private IncrementalCharSequence(@NonNull final char[] input, @NonNull final char[] chars, final int index) {
            this.input = input;
            this.chars = chars;
            this.index = index;
            if (index + 1 < chars.length) {
                this.subIncrementalCharSequence = new IncrementalCharSequence(input, chars, index + 1);
            } else {
                this.subIncrementalCharSequence = null;
            }
            currentIndex = 0;
            chars[index] = input[currentIndex];
        }
    
        /**
         * Increment the char sequence
         *
         * @return {@code true} if incremented, {@code false} if rolled over to zero index
         */
        public boolean increment() {
            if (subIncrementalCharSequence != null && subIncrementalCharSequence.increment()) {
                return true;
            } else if (currentIndex < input.length) {
                chars[index] = input[currentIndex];
                currentIndex++;
                return true;
            } else {
                currentIndex = 0;
                chars[index] = input[currentIndex];
                return false;
            }
        }
    }
    

    【讨论】:

      【解决方案6】:

      伪代码

      initialize globalComb, an empty array of strings (to keep all combination)
      initialize prevComb, an array of strings with an empty string (the previous set of combination)
      while(the length of first string in prevComb is not of desired length)
          initialize temp,  an empty array of strings (a temporary one)
          for(each string s in prevComb)
              for(each char c in the alphabet)
                  insert s + c in temp
                  insert s + c in globalComb
              end for
          end for
          lastComb = temp
      return globalComb
      

      globalComb 的大小必须是 sum(k=1, k=desired length)26^k。如果所需的长度是 26,我怀疑普通笔记本电脑是否可以容纳这样的字符串数组。您可以将字符串打印出来,而不是存储在全局数组中。

      【讨论】:

        【解决方案7】:

        我想出了这段代码 这将运行到 8 个小字/字母
        例如。如果您只使用大写字母 A 到 Z:
        一个

        ...
        ...
        ZZZZZZZY
        ZZZZZZZZ

        char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
        for (int i = 0; i < ch.length; i++) {
            char c1 = ch[i];
            for (int j = 0; j < ch.length; j++) {
                char c2 = ch[j];
                for (int k = 0; k < ch.length; k++) {
                    char c3 = ch[k];
                    for (int l = 0; l < 10; l++) {
                        char c4 = ch[l];
                        for (int m = 0; m < 10; m++) {
                            char c5 = ch[m];
                            for (int n = 0; n < 10; n++) {
                                char c6 = ch[n];
                                for (int o = 0; o < 10; o++) {
                                    char c7 = ch[o];
                                    for (int p = 0; p < 10; p++) {
                                        char c8 = ch[p];
                                        currentString = "" + c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8;
                                        System.out.println(currentString);
        
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-16
          相关资源
          最近更新 更多