我需要找到一种方法在指定的字符串而不是开头启动此字符串生成算法。例如,不是从“aaaa”开始,而是从“baxi”开始,然后遍历字符串空间的其余部分。
private static String Charset = "abcdefghijklmnopqrstuvwxyz";
/// <summary>
/// Start Brute Force.
/// </summary>
/// <param name="length">Words length.</param>
public static void StartBruteForce(int length)
{
StringBuilder sb = new StringBuilder(length);
char currentChar = Charset[0];
for (int i = 1; i <= length; i++)
{
sb.Append(currentChar);
}
int counter = 0;
ChangeCharacters(0, sb, length, ref counter);
Console.WriteLine(counter);
}
private static void ChangeCharacters(int pos, StringBuilder sb, int length, ref int counter)
{
for (int i = 0; i <= Charset.Length - 1; i++)
{
sb[pos] = Charset[i];
if (pos == length - 1)
{
counter++;
Console.WriteLine(sb.ToString());
}
else
{
ChangeCharacters(pos + 1, sb, length, ref counter);
}
}
}
最佳答案
你所拥有的非常接近,但看起来问题的根源是 ChangeCharacters
被写入总是从第一个可能的字符串开始,例如每个位置的字符始终从字母表的第一个字母开始(示例中为 'a'
)。您需要在起始字符串中的每个位置处以已存在的字母开始第一遍,然后后续遍将从生成的字母表的第一个字符开始。
因此,对于您已有的代码,您需要进行以下更改:
- 传递一个标志,表明这是第一次传递。
- 根据第一遍标志选择循环的起点。
- 将第一遍标志传递给您的递归调用。
- 在每个位置第一次通过后重置标志。
- 初始化
StringBuilder
使用您的起始字符串,而不是当前的默认起始点。
为了清楚起见,还有一些其他项目值得更改。这些都不是正确性所必需的,但它们确实使代码更易于阅读和理解:
- 无需传递
length
,因为它始终与sb.Length
相同。重复的信息充其量会迫使读者跟踪更多信息,而在最坏的情况下,如果以后的代码更改破坏了这种关系,可能会导致错误。 使用从零开始索引的语言中索引循环的标准习惯用法是“端点独占”形式,使用“小于”(甚至“不等于”)比较器,因为这可以避免溢出边界处的错误,例如
i < length
而不是i <= length - 1
。大多数代码阅读者本能地理解这个习语,而包含端点的形式通常会迫使读者考虑为什么需要反习语。无需通过引用传递计数器,只需返回生成的字符串计数即可。不改变外部状态的方法通常被称为“纯”或“函数”,通常更容易理解。 (但是请注意,您还可以在正在传递的
StringBuilder
中获得状态。)- 作为进一步的改进,我什至建议返回
IEnumerable<string>
,这不仅消除了跟踪计数的需要,而且还允许调用者确定如何处理字符串,而不是在您的方法内部做出该决定(例如调用Console.WriteLine
并递增计数器)。
- 作为进一步的改进,我什至建议返回
将所有这些放在一起,您的代码就变成了这样(用注释指出正在发生的更改或建议):
public static void StartBruteForce(string start)
{
/*change 5*/ StringBuilder sb = new StringBuilder(start);
/*sugg 3*/ int counter = ChangeCharacters(0, /*change 1*/ true, sb);
Console.WriteLine(counter);
}
private static int ChangeCharacters(int pos, /*change 1*/ bool firstPass , StringBuilder sb)
{
/*sugg 3*/ int counter = 0;
for (int i = /*change 2*/ firstPass ? Charset.IndexOf(sb[pos]) : 0; /*sugg 2*/ i < Charset.Length; i++)
{
sb[pos] = Charset[i];
if (pos == /*sugg 1*/ sb.Length - 1)
{
counter++;
Console.WriteLine(sb.ToString());
}
else
{
/*sugg 3*/ counter += ChangeCharacters(pos + 1, /*change 3*/ firstPass, sb);
/*change 4*/ firstPass = false;
}
}
/*sugg 3*/ return counter;
}
关于c# 从指定点开始暴力破解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14524808/