C# | Как подправить алгоритм?
Я захотел написать свой генератор пароля на C#, который спрашивал: длину пароля, сколько спец. символов, сколько чисел. Конечно, всё было без проблем, кроме одной. Если я ставил, например, длину 7, спец. символов 2, чисел 2, то он длину сделал правильно, кол-во чисел правильно, но вот только спец. символ только один. Он сгенерировал 3, 4 индекс (буквы), но не оставшийся спец. символ. Так вот. Как мне сделать чтобы все условия были бы выполнены? Мой код
using System;
using System.Collections.Generic;
using static System.Console;
var random = new Random();
var userPasswordData = ReadLine()?.Split(' ');
var lengthRequired = int.Parse(userPasswordData?[0] ?? "7");
var specialSymbolsRequired = int.Parse(userPasswordData?[1] ?? "2");
var numbersRequired = int.Parse(userPasswordData?[2] ?? "2");
var charactersList = new List<string>
{
"0123456789",
"!@#$%&*",
// ReSharper disable once StringLiteralTypo
"abcdefghijklmnopqrstuvwxyz",
// ReSharper disable once StringLiteralTypo
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
};
var generatedPasswordData = new Dictionary<string, int>
{
{"SpecialSymbols", 0},
{"Numbers", 0}
};
var generatedPassword = "";
for (var i = 1; i <= lengthRequired; i++)
{
var rowIndex = 0;
var columnIndex = 0;
// If it's first letter of generation password.
if (i == 1)
{
rowIndex = random.Next(2, charactersList.Count);
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
continue;
}
do
{
rowIndex = random.Next(0, charactersList.Count);
// If row at numbers
if (rowIndex == 0)
{
if (generatedPasswordData["Numbers"] < numbersRequired)
{
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
generatedPasswordData["Numbers"] += 1;
break;
}
}
// If row at Special Symbols
else if (rowIndex == 1)
{
if (generatedPasswordData["SpecialSymbols"] < specialSymbolsRequired)
{
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
generatedPasswordData["SpecialSymbols"] += 1;
break;
}
}
// If row at letters.
else
{
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
break;
}
} while (true);
}
WriteLine(generatedPassword);
Ответы (3 шт):
Лови
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
var random = new Random();
int gh = 0;
int gy = 0;
var userPasswordData = ReadLine()?.Split(' ');
var lengthRequired = 7; //int.Parse(userPasswordData?[0] ?? "7");
var specialSymbolsRequired = 5; //int.Parse(userPasswordData?[1] ?? "2");
var numbersRequired = 2;// int.Parse(userPasswordData?[2] ?? "2");
var charactersList = new List<string>
{
"0123456789",
"!@#$%&*",
// ReSharper disable once StringLiteralTypo
"abcdefghijklmnopqrstuvwxyz",
// ReSharper disable once StringLiteralTypo
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
};
var generatedPasswordData = new Dictionary<string, int>
{
{"SpecialSymbols", 0},
{"Numbers", 0}
};
var generatedPassword = "";
for (var i = 1; i <= lengthRequired; i++)
{
var rowIndex = 0;
var columnIndex = 0;
do
{
rowIndex = random.Next(0, charactersList.Count);
// If row at numbers
if (rowIndex == 0)
{
if (generatedPasswordData["Numbers"] < numbersRequired)
{
gy++;
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
generatedPasswordData["Numbers"] += 1;
break;
}
}
// If row at Special Symbols
if (rowIndex == 1)
{
if (generatedPasswordData["SpecialSymbols"] < specialSymbolsRequired)
{
gh++;
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
generatedPasswordData["SpecialSymbols"] += 1;
break;
}
}
// If row at letters.
else if (gh + gy == specialSymbolsRequired+numbersRequired)
{
columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
break;
}
} while (true);
}
WriteLine(generatedPassword);
Console.ReadLine();
}
}
}
Я предлагаю по другому подойти к решению. Сначала создаём маску будущего пароля, которая соответствует нашим условиям. Эта маска содержит индексы на наборы символов. Затем "перетасовываем" маску и в цикле вычисляем новые символы для пароля.
Random random = new Random();
var lengthRequired = 7;
var specialSymbolsRequired = 2;
var numbersRequired = 2;
var charactersList = new List<string>
{
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"!@#$%&*"
};
String mask = (new String('1', numbersRequired) + new String('2', specialSymbolsRequired)).PadRight(lengthRequired-1, '0');
String smask = '0' + new string(mask.ToCharArray().OrderBy(x => random.NextDouble()).ToArray());
String generatedPassword = "";
for (int i = 0; i < lengthRequired; i++)
{
int rowIndex = smask[i] - 48;
int columnIndex = random.Next(0, charactersList[rowIndex].Length);
generatedPassword += charactersList[rowIndex][columnIndex];
}
Console.WriteLine(generatedPassword);
smask - это перетасованная маска. '0' в начале гарантирует, что первый символ будет буква.
Рекомендую найти более качественный shuffle-алгоритм.
Ошибка в вашем алгоритме кроется в том, что вы не контролируете количество сгенерированных букв. Что вам нужно поменять в вашем алгоритме, чтобы все работало правильно?
Вычислить требуемое количество букв, которое должно содержать итоговая строка:
var lettersRequired = lengthRequired - specialSymbolsRequired - numbersRequired - 1; // -1 учитывает первый символ пароля, который обязательно должен быть буквойДобавить в словарь
generatedPasswordDataсчетчик "Letters":var generatedPasswordData = new Dictionary<string, int> { {"SpecialSymbols", 0}, {"Numbers", 0}, {"Letters", 0} };В месте, где вы генерируете буквы, добавьте аналогичное условие на ограничение количества сгенерированных букв:
// If row at letters. else if (generatedPasswordData["Letters"] < lettersRequired) { columnIndex = random.Next(0, charactersList[rowIndex].Length); generatedPassword += charactersList[rowIndex][columnIndex]; generatedPasswordData["Letters"]++; break; }
P.S. Я бы на вашем месте вынес код генерации символов в отдельный класс. Возможно, чуть позже дополню ответ с улучшениями вашего кода.