C#:带模式的蛮力
C#: Brute Force with pattern
我想知道是否有人可以帮助我。我正在尝试做一个将遵循特定模式的蛮力算法。
我可以通过一些草率的代码工作让它输出模式,但这对我来说有点新鲜。我真的不知道如何从这里继续。如果您知道我该怎么做,我将不胜感激。
模式看起来像这样
AA0AA0A0
所以我希望它从 AA0AA0A0 暴力破解到 AA9AA9A9 然后它会去 AA0AA0B0
我非常感谢所有建议。我已经尝试 google 一些解决方案,但没有真正找到任何特别的东西。
过程说明:
从生成第一个字符串 AA0AA0A0 开始。
然后它一直生成到 AA0AA0A9。
然后它从下一个数字开始,所以它将是 AA0AA1A0。
所以它将一直计数到 AA9AA9AA9,这将导致它跳转到 AA0AA0B0。
还更新了代码,现在可以使用了。
private static char[] fCharList = { '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' };
private static char[] fNumList = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
static void Main(string[] args)
{
StartBruteForce(8);
}
public static void StartBruteForce(int length)
{
StringBuilder sb = new StringBuilder(length);
char currentChar = fCharList[0];
char currentNum = fNumList[0];
for (int i = 1; i <= 2; i++)
{
sb.Append(currentChar);
}
for (int i = 1; i <= 1; i++)
{
sb.Append(currentNum);
}
for (int i = 1; i <= 2; i++)
{
sb.Append(currentChar);
}
for (int i = 1; i <= 1; i++)
{
sb.Append(currentNum);
}
for (int i = 1; i <= 2; i++)
{
sb.Append(currentChar);
}
for (int i = 2; i <= 1; i++)
{
sb.Append(currentNum);
}
//Console.WriteLine(sb);
//Console.ReadLine();
ChangeCharacters(7, sb, length);
}
private static StringBuilder ChangeCharacters(int pos, StringBuilder sb, int length)
{
for (int i = 0; i <= sb.Length - 1; i++)
{
//sb.setCharAt(pos, fCharList[i]);
sb.Replace(sb[pos], fNumList[i], pos, 1);
//sb.Replace(sb[pos], fCharList[i], pos, 1);
if (pos == length - 1)
{
// Write the Brute Force generated word.
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
else
{
ChangeCharacters(pos - 1, sb, length);
}
}
return sb;
}
我认为如果你有一个 returns 下一个 "pattern" 字符串的函数会更好,这样你就可以有一个 for 循环。
像这样:
public static string Next(string pattern)
{
bool carry = true;
var sb = new List<char>();
int t;
for(int i = pattern.Length - 1; i >= 0; i--)
{
if (!carry)
{
sb.Insert(0, pattern[i]);
continue;
}
if (char.IsDigit(pattern[i]))
{
t = int.Parse(pattern[i].ToString()) + 1;
if (t == 10)
{
sb.Insert(0, '0');
carry = true;
}
else
{
sb.Insert(0, t.ToString()[0]);
carry = false;
}
}
else
{
t = (int)pattern[i] + 1;
if (t == 91)
{
sb.Insert(0, 'A');
carry = true;
}
else
{
sb.Insert(0, Convert.ToChar(t));
carry = false;
}
}
}
return new string(sb.ToArray());
}
一些简单的循环将迭代并每次构建一个新字符串。您可以将字符转换为 int 并返回。所以你可以把每个字母当作一个数字。这假设您的模式始终为 AA0AA0A0。如果这种情况发生变化,您需要使程序更智能。
static void Main(string[] args)
{
foreach (var results in BruteForce())
{
Console.WriteLine(results);
}
}
public static IEnumerable<String> BruteForce()
{
const int firstLetter = 'A';
const int lastLetter = 'Z';
for (var firstPos = firstLetter; firstPos <= lastLetter; firstPos++)
{
for (var secondPos = firstLetter; secondPos <= lastLetter; secondPos++)
{
for (var thirdPos = 0; thirdPos <= 9; thirdPos++)
{
for (var fourthPos = firstLetter; fourthPos <= lastLetter; fourthPos++)
{
for (var fifthPos = firstLetter; fifthPos <= lastLetter; fifthPos++)
{
for (var sixthPos = 0; sixthPos <= 9; sixthPos++)
{
for (var sevethPos = firstLetter; sevethPos <= lastLetter; sevethPos++)
{
for (var eighthPos = 0; eighthPos <= 9; eighthPos++)
{
yield return
String.Join(string.Empty,
(char) firstPos,
(char) secondPos,
thirdPos,
(char) fourthPos,
(char) fifthPos,
sixthPos,
(char) sevethPos,
eighthPos);
}
}
}
}
}
}
}
}
}
我认为最简单的方法是将模式一分为二;一个用于数字,一个用于字符。数字从 000
进步到 999
,字符从 AAAAA
进步到 ZZZZZ
。然后,您只需将数字拼接到字符的正确位置即可。
IEnumerable<string> Strings()
{
var digits = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var chars = Enumerable.Range((int)'A', (int)'Z' - (int)'A' + 1).Select(i => (char)i).ToArray();
for (var c = 0L; c < Math.Pow(chars.Length, 5); ++c)
{
var cstr = chars[(c / (chars.Length * chars.Length * chars.Length * chars.Length) % chars.Length)].ToString()
+ chars[(c / (chars.Length * chars.Length * chars.Length) % chars.Length)]
+ chars[(c / (chars.Length * chars.Length) % chars.Length)]
+ chars[(c / (chars.Length) % chars.Length)]
+ chars[(c % chars.Length)];
for (var i = 0L; i < 999; ++i)
{
var istr = (i / 100 % 10).ToString()
+ (i / 10 % 10).ToString()
+ (i % 10).ToString();
var str = cstr.Substring(0, 2) + istr.Substring(0, 1) + cstr.Substring(2, 2) + istr.Substring(1, 1) + cstr.Substring(4, 1) + istr.Substring(2, 1);
yield return str;
}
}
}
像这样使用它:
var early = Strings().Take(15);
var late = Strings().Skip(1234).Take(15);
foreach (var s in early.Concat(late))
{
Console.WriteLine(s);
}
将打印此:
AA0AA0A0
AA0AA0A1
AA0AA0A2
AA0AA0A3
AA0AA0A4
AA0AA0A5
AA0AA0A6
AA0AA0A7
AA0AA0A8
AA0AA0A9
AA0AA1A0
AA0AA1A1
AA0AA1A2
AA0AA1A3
AA0AA1A4
AA2AA3B5
AA2AA3B6
AA2AA3B7
AA2AA3B8
AA2AA3B9
AA2AA4B0
AA2AA4B1
AA2AA4B2
AA2AA4B3
AA2AA4B4
AA2AA4B5
AA2AA4B6
AA2AA4B7
AA2AA4B8
AA2AA4B9
public static IEnumerable<String> loop()
{
char[] chars = new char[] { 'a', 'b', 'c' };
for (int i = 0; i < 3000; i++)
{
string s = string.Format("aa{0}aa{1}{2}{3}", (i % 1000) / 100, (i % 100) / 10, chars[(i % 10000) / 1000], i % 10);
System.Diagnostics.Debug.WriteLine(s);
yield s;
}
}
首先阅读我关于如何计算笛卡尔积的文章:
https://blogs.msdn.microsoft.com/ericlippert/2010/06/28/computing-a-cartesian-product-with-linq/
现在应该清楚如何进行了:
var results = from product in CartesianProduct(
new[] { charList, charList, charList, charList, charList, numList, numList, numList } )
let a = product.ToArray()
select "" + a[0] + a[1] + a[5] + a[2] + a[3] + a[6] + a[4] + a[7];
领略 LINQ 的威力:用一条语句解决您的组合问题。
备选方案:
做一个从0上升到10 * 10 * 10 * 26 * 26 * 26 * 26 * 26 - 1的计数器,应该是long。
在计数器的每个刻度上,让数字为 c
。最下面的数字是 '0' + c%10
。下一个数字是 '0' + c/10%10
。接下来是'0' + c/(10*10)%10
。最下面的字母是 'A' + c/(10*10*10)%26
。下一个字母是 'A' + c/(10*10*10*26)%26
。依此类推
将字母和数字按正确的顺序放在一起,得到结果。
将其转换为代码留作练习。
另一种替代解决方案:
var results = from a0 in charList
from a1 in charList
from a2 in charList
from a3 in charList
from a4 in charList
from a5 in numList
from a6 in numList
from a7 in numList
select "" + a0 + a1 + a5 + a2 + a3 + a6 + a4 + a7;
再次感谢 LINQ,这是一个不错的单语句解决方案。
我想知道是否有人可以帮助我。我正在尝试做一个将遵循特定模式的蛮力算法。 我可以通过一些草率的代码工作让它输出模式,但这对我来说有点新鲜。我真的不知道如何从这里继续。如果您知道我该怎么做,我将不胜感激。
模式看起来像这样
AA0AA0A0
所以我希望它从 AA0AA0A0 暴力破解到 AA9AA9A9 然后它会去 AA0AA0B0
我非常感谢所有建议。我已经尝试 google 一些解决方案,但没有真正找到任何特别的东西。
过程说明: 从生成第一个字符串 AA0AA0A0 开始。 然后它一直生成到 AA0AA0A9。 然后它从下一个数字开始,所以它将是 AA0AA1A0。 所以它将一直计数到 AA9AA9AA9,这将导致它跳转到 AA0AA0B0。
还更新了代码,现在可以使用了。
private static char[] fCharList = { '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' };
private static char[] fNumList = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
static void Main(string[] args)
{
StartBruteForce(8);
}
public static void StartBruteForce(int length)
{
StringBuilder sb = new StringBuilder(length);
char currentChar = fCharList[0];
char currentNum = fNumList[0];
for (int i = 1; i <= 2; i++)
{
sb.Append(currentChar);
}
for (int i = 1; i <= 1; i++)
{
sb.Append(currentNum);
}
for (int i = 1; i <= 2; i++)
{
sb.Append(currentChar);
}
for (int i = 1; i <= 1; i++)
{
sb.Append(currentNum);
}
for (int i = 1; i <= 2; i++)
{
sb.Append(currentChar);
}
for (int i = 2; i <= 1; i++)
{
sb.Append(currentNum);
}
//Console.WriteLine(sb);
//Console.ReadLine();
ChangeCharacters(7, sb, length);
}
private static StringBuilder ChangeCharacters(int pos, StringBuilder sb, int length)
{
for (int i = 0; i <= sb.Length - 1; i++)
{
//sb.setCharAt(pos, fCharList[i]);
sb.Replace(sb[pos], fNumList[i], pos, 1);
//sb.Replace(sb[pos], fCharList[i], pos, 1);
if (pos == length - 1)
{
// Write the Brute Force generated word.
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
else
{
ChangeCharacters(pos - 1, sb, length);
}
}
return sb;
}
我认为如果你有一个 returns 下一个 "pattern" 字符串的函数会更好,这样你就可以有一个 for 循环。
像这样:
public static string Next(string pattern)
{
bool carry = true;
var sb = new List<char>();
int t;
for(int i = pattern.Length - 1; i >= 0; i--)
{
if (!carry)
{
sb.Insert(0, pattern[i]);
continue;
}
if (char.IsDigit(pattern[i]))
{
t = int.Parse(pattern[i].ToString()) + 1;
if (t == 10)
{
sb.Insert(0, '0');
carry = true;
}
else
{
sb.Insert(0, t.ToString()[0]);
carry = false;
}
}
else
{
t = (int)pattern[i] + 1;
if (t == 91)
{
sb.Insert(0, 'A');
carry = true;
}
else
{
sb.Insert(0, Convert.ToChar(t));
carry = false;
}
}
}
return new string(sb.ToArray());
}
一些简单的循环将迭代并每次构建一个新字符串。您可以将字符转换为 int 并返回。所以你可以把每个字母当作一个数字。这假设您的模式始终为 AA0AA0A0。如果这种情况发生变化,您需要使程序更智能。
static void Main(string[] args)
{
foreach (var results in BruteForce())
{
Console.WriteLine(results);
}
}
public static IEnumerable<String> BruteForce()
{
const int firstLetter = 'A';
const int lastLetter = 'Z';
for (var firstPos = firstLetter; firstPos <= lastLetter; firstPos++)
{
for (var secondPos = firstLetter; secondPos <= lastLetter; secondPos++)
{
for (var thirdPos = 0; thirdPos <= 9; thirdPos++)
{
for (var fourthPos = firstLetter; fourthPos <= lastLetter; fourthPos++)
{
for (var fifthPos = firstLetter; fifthPos <= lastLetter; fifthPos++)
{
for (var sixthPos = 0; sixthPos <= 9; sixthPos++)
{
for (var sevethPos = firstLetter; sevethPos <= lastLetter; sevethPos++)
{
for (var eighthPos = 0; eighthPos <= 9; eighthPos++)
{
yield return
String.Join(string.Empty,
(char) firstPos,
(char) secondPos,
thirdPos,
(char) fourthPos,
(char) fifthPos,
sixthPos,
(char) sevethPos,
eighthPos);
}
}
}
}
}
}
}
}
}
我认为最简单的方法是将模式一分为二;一个用于数字,一个用于字符。数字从 000
进步到 999
,字符从 AAAAA
进步到 ZZZZZ
。然后,您只需将数字拼接到字符的正确位置即可。
IEnumerable<string> Strings()
{
var digits = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var chars = Enumerable.Range((int)'A', (int)'Z' - (int)'A' + 1).Select(i => (char)i).ToArray();
for (var c = 0L; c < Math.Pow(chars.Length, 5); ++c)
{
var cstr = chars[(c / (chars.Length * chars.Length * chars.Length * chars.Length) % chars.Length)].ToString()
+ chars[(c / (chars.Length * chars.Length * chars.Length) % chars.Length)]
+ chars[(c / (chars.Length * chars.Length) % chars.Length)]
+ chars[(c / (chars.Length) % chars.Length)]
+ chars[(c % chars.Length)];
for (var i = 0L; i < 999; ++i)
{
var istr = (i / 100 % 10).ToString()
+ (i / 10 % 10).ToString()
+ (i % 10).ToString();
var str = cstr.Substring(0, 2) + istr.Substring(0, 1) + cstr.Substring(2, 2) + istr.Substring(1, 1) + cstr.Substring(4, 1) + istr.Substring(2, 1);
yield return str;
}
}
}
像这样使用它:
var early = Strings().Take(15);
var late = Strings().Skip(1234).Take(15);
foreach (var s in early.Concat(late))
{
Console.WriteLine(s);
}
将打印此:
AA0AA0A0
AA0AA0A1
AA0AA0A2
AA0AA0A3
AA0AA0A4
AA0AA0A5
AA0AA0A6
AA0AA0A7
AA0AA0A8
AA0AA0A9
AA0AA1A0
AA0AA1A1
AA0AA1A2
AA0AA1A3
AA0AA1A4
AA2AA3B5
AA2AA3B6
AA2AA3B7
AA2AA3B8
AA2AA3B9
AA2AA4B0
AA2AA4B1
AA2AA4B2
AA2AA4B3
AA2AA4B4
AA2AA4B5
AA2AA4B6
AA2AA4B7
AA2AA4B8
AA2AA4B9
public static IEnumerable<String> loop()
{
char[] chars = new char[] { 'a', 'b', 'c' };
for (int i = 0; i < 3000; i++)
{
string s = string.Format("aa{0}aa{1}{2}{3}", (i % 1000) / 100, (i % 100) / 10, chars[(i % 10000) / 1000], i % 10);
System.Diagnostics.Debug.WriteLine(s);
yield s;
}
}
首先阅读我关于如何计算笛卡尔积的文章:
https://blogs.msdn.microsoft.com/ericlippert/2010/06/28/computing-a-cartesian-product-with-linq/
现在应该清楚如何进行了:
var results = from product in CartesianProduct(
new[] { charList, charList, charList, charList, charList, numList, numList, numList } )
let a = product.ToArray()
select "" + a[0] + a[1] + a[5] + a[2] + a[3] + a[6] + a[4] + a[7];
领略 LINQ 的威力:用一条语句解决您的组合问题。
备选方案:
做一个从0上升到10 * 10 * 10 * 26 * 26 * 26 * 26 * 26 - 1的计数器,应该是long。
在计数器的每个刻度上,让数字为
c
。最下面的数字是'0' + c%10
。下一个数字是'0' + c/10%10
。接下来是'0' + c/(10*10)%10
。最下面的字母是'A' + c/(10*10*10)%26
。下一个字母是'A' + c/(10*10*10*26)%26
。依此类推将字母和数字按正确的顺序放在一起,得到结果。
将其转换为代码留作练习。
另一种替代解决方案:
var results = from a0 in charList
from a1 in charList
from a2 in charList
from a3 in charList
from a4 in charList
from a5 in numList
from a6 in numList
from a7 in numList
select "" + a0 + a1 + a5 + a2 + a3 + a6 + a4 + a7;
再次感谢 LINQ,这是一个不错的单语句解决方案。