蛮力算法仅打印 0

Brute Force Algorithm Prints Only 0

我正在使用 C# 创建一个蛮力算法(用于教育目的),但我遇到了一个错误。

我的暴力破解方式就像一个时钟 - 字符串中的最后一个字符从 0 上升到程序开始时设置的字符数组中的最后一个字符,当它到达结尾时 - 重置为 0 并增加前一个字符加 1,依此类推。

然而,下面的代码只打印 0:

// Array with characters to use in Brute Force Algorithm.
    // You can remove or add more characters in this array.
    private static char[] fCharList =
    {
        '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j' ,'k','l','m','n','o','p',
                    'q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','C','L','M','N','O','P',
                    'Q','R','S','T','U','V','X','Y','Z','~','!','@','#','$','%','^','&','*','(',')','[',']','{','}','.',',','/','?','\'','|','"',';',':','<','>','\','=','-','+','`','_'
    };

    private static String password;

    static void Main(string[] args)
    {
        Console.WriteLine("Enter the password: ");
        password = Console.ReadLine();
        Bruteforce();
    }

    // The Bruteforce algorithm
    // Goes like a clock cycle: Last index goes from fCharList[0] to fCharList[fCharList.Length - 1] 
    // then resets and last index -1 increases and so on.

    public static String Bruteforce()
    {

        String currPass = fCharList[0].ToString();
        bool foundPass = false;

        for (int i = 1; !foundPass; i++)
        {
            // If there's a need to increase (foundd fCharList[fCharList.Length - 1] in the String)
            if (currPass.Contains(fCharList[fCharList.Length - 1]))
            {
                //If no need to increase the whole length and reset all the characters
                if (!(currPass.IndexOf(fCharList[fCharList.Length - 1]) == 0))
                {
                    String updateCurrPass = "";
                    for (int j = currPass.Length - 1; j >= currPass.IndexOf(fCharList[fCharList.Length - 1]); j--)
                    {
                        updateCurrPass += fCharList[0].ToString();
                    }
                    currPass.Insert(currPass.IndexOf(fCharList[fCharList.Length - 1]) - 1, fCharList[Array.IndexOf(fCharList, currPass.ElementAt<char>(currPass.IndexOf(fCharList[fCharList.Length - 1]) - 1)) + 1].ToString() + updateCurrPass);
                }
            }
            else // If no cycle ended - continue increasing last "digit"
            {
                currPass.Insert(currPass.Length - 1, fCharList[Array.IndexOf(fCharList, currPass.ElementAt(currPass.Length - 1)) + 1].ToString());
            }
            Console.Write(currPass + "  ");

        }
        return "";
    }

我尝试了 currPass.Insert(currPass.Length - 1, fCharList[Array.IndexOf(fCharList, currPass.ElementAt(currPass.Length - 1)) + 1].ToString()); 的所有可能问题(因为我怀疑问题可能发生在打印过程本身),但没有成功。

我也试过用断点和纸来跟踪代码,还是不行。 如果有人能帮我解决这个问题,我会很高兴。

编辑: 下面,许多人建议 updateCurrPass += fCharList[0].ToString(); 应该是 updateCurrPass += fCharList[j].ToString();。我还没有太深入地检查那个选项,但为了更好地解释我的情况,我希望它像时钟周期一样工作 - 当最后一位数字是 fCharList 中的最新字符时,前一位数字增加等等.提到的代码重置已到达最后一个字符的数字。 (因此,如果字符串 currPass 是 "0aa___"(_ 是最后一个字符),它将变为 0ab000updateCurrPass 添加 3 个 0,而函数的其余部分增加a 到 b.

你认为是因为你这样分配 updateCurrPass 吗? :

for (int j = currPass.Length - 1; j >= currPass.IndexOf(fCharList[fCharList.Length - 1]); j--)
{
     updateCurrPass += fCharList[0].ToString();
}

我认为它应该涉及 j 或其他东西:

for (int j = currPass.Length - 1; j >= currPass.IndexOf(fCharList[fCharList.Length - 1]); j--)
{
     updateCurrPass += fCharList[j].ToString();
}

添加代码:

下面的代码将不执行任何操作,因为该函数将 return 函数(而不是更改通过参数传递的对象),您应该添加 currPass = currPass.Insert(...) 如前所述通过@Rafalon

else // If no cycle ended - continue increasing last "digit"
{
    currPass.Insert(currPass.Length - 1, fCharList[Array.IndexOf(fCharList, currPass.ElementAt(currPass.Length - 1)) + 1].ToString());
}

改用这个:

else // If no cycle ended - continue increasing last "digit"
{
    currPass = currPass.Insert(currPass.Length - 1, fCharList[Array.IndexOf(fCharList, currPass.ElementAt(currPass.Length - 1)) + 1].ToString());
}

所述,您必须在循环中使用 j 而不是 0。 (也可能不是,我不确定我是否理解你的算法)

但还有更多:

你必须注意,在C#中,String是不可变的,这意味着currPass.Insert(...)本身什么都不做,你必须像currPass = currPass.Insert(...);那样重新分配结果

但是嘿,我认为你把算法过于复杂了。

我会做的:

string currPass = fCharList[0].ToString();
bool found = false;
while(!found)
{
    currPass = IncreasePassword(currPass);
    found = CheckPass(currPass);
}

IncreasePassword:

public static string IncreasePassword(string pass)
{
    bool changed = false;
    StringBuilder sb = new StringBuilder(pass);
    // loop through pass until we change something 
    // or we reach the end (what comes first)
    for(int i = 0; i < pass.Length && !changed; i++)
  //for(int i = pass.Length - 1; i >= 0 && !changed; i--)  
    {
        int index = Array.IndexOf(fCharList, sb[i]);
        // if current char can be increased
        if(index < fCharList.Length - 1)
        {
            // if we have __012 then we'll go on 00112
            // so here we replace the left __ with 00
            for(int j = i - 1; j >= 0 && sb[j] == fCharList[fCharList.Length - 1]; j--)
          //for(int j = i + 1; j < sb.Length && sb[j] == fCharList[fCharList.Length - 1]; j++)
            {
               sb[j] = fCharList[0];
            }
            // and here we increase the current char
            sb[i] = fCharList[index + 1];
            changed = true;
        }
    }
    // if we didn't change anything, it means every char were '_'
    // so we start with a fresh new full-of-0 string
    if(!changed)
    {
        return "".PadLeft(pass.Length + 1, fCharList[0]);
    }
    return sb.ToString();
}

Live example.


说明

这将从左到右按以下方式工作:
假设我们的 fCharList{ '0','1','2' } 以进行简化。
我们将有:

0
1
2
00
10
20
01
11
21
02
12
22
000
100
200
010
110
210
020
....

测试结果

这是它从 :

提供的反向输入(因为我的解决方案是相反的)
Input        Output
0            1
1            2
P            Q
_            00
00           10
_0           01
__CBA        00DBA
____         00000

请注意,您的 fCharList 损坏 ,因为 C 而不是 K

虽然其他答案指出了具体问题,但我可以建议您更广泛的问题是您试图一次做太多事情吗?您很可能能够将整个算法写成一个片段并对其进行调整,直到它起作用,但是这样做非常困难,而且最终也很难确信它是正确的。您会发现将算法分解为更小的函数并单独测试它们以确认它们是否符合您的预期更容易。

例如,您可以分解出计算 "given the last password I checked, what is the next password in sequence to consider" 的算法部分?这是算法的核心,它可以从迭代 所有 可能的密码并根据当前密码对其进行测试的工作中分离出来。而且测试起来更容易!例如,您可以像这样使用测试数据:

Input             Expected output
"0"               "1"
"1"               "2"
"P"               "Q"
"_"               "00"
"00"              "01"
"0_"              "10"
"ABC__"           "ABD00"
"____"            "00000"

当您发现您的函数没有为这些测试中的部分或全部给出正确答案时,与尝试调试整个算法相比,您要做的工作更小、更具体,可以找出问题所在立刻。