C#. Генерация строки из случайных символов.

Задача

Сгенерировать строку, состоящую из случайных символов. Немного дополним задачу, строка будет состоять из случайных символов, а сами символы будут взяты из заранее заданного определенного набора. Например, строчные и заглавные латинские буквы, цифры, знаки препинания или любые другие заданные символы в любой комбинации.
Такая штуковина вполне может пригодиться для генерации, например, пароля из заданного набора символов

Решение

Делается это довольно просто. Поручим формирование строки отдельной функции.
Во входных параметрах передадим ей строку, содержащую набор символов, из которых будет сформирована выходная случайная строка (параметр Alphabet) и длину генерируемой строки (параметр Length)

string GenRandomString(string Alphabet, int Length)
{
	...
}

Внутри функции.

//создаем объект Random, генерирующий случайные числа
Random rnd = new Random();
//объект StringBuilder с заранее заданным размером буфера под результирующую строку
StringBuilder sb = new StringBuilder(Length-1);
//переменную для хранения случайной позиции символа из строки Alphabet
int Position = 0;

Далее в цикле генерируем случайную строку:

for (int i = 0; i < Length; i++)
            {
                //получаем случайное число от 0 до последнего
                //символа в строке Alphabet
                Position = rnd.Next(0, Alphabet.Length-1);
                //добавляем выбранный символ в объект
                //StringBuilder
                sb.Append(Alphabet[Position]);                
            }

Возвращаем сгенерированную строку:

return sb.ToString();

Код функции на PasteBin

Пример использования функции

txtReturn.Text = GenRandomString("QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm", 10);

возвращает строку случайных символов длиной 10 знаков, состоящую из заглавных и строчных букв английского алфавита.


Немного об оптимизации

Или почему стоит использовать StringBuilder вместо подобной довольно обычной конструкции.
Перед циклом заводим строковую переменную:
string Ret = "";
В цикле используем Ret = Ret + Alphabet[Position]; вместо sb.Append(Alphabet[Position]);
И в итоге возвращаем значение return Ret;

Да потому что, в данном конкретном случае, использование StringBuilder дает реальный выигрыш в скорости:

Проблема конкатенации большого массива строк, при которой результирующая строка очень быстро и сильно растёт, очень реальна, и совет использовать StringBuilder для конкатенации очень правильный.
[...]
На самом деле выражение x += "!"; абсолютно эквивалентно выражению x = x+"!";. Здесь конкатенация — это создание полностью новой строки, для которой выделяется нужный объём памяти, в который копируется содержимое существующего значения x, а потом копируется содержимое конкатенируемой строки. По мере того, как результирующая строка растёт, возрастает и количество данных, которые всё время копируются туда-сюда [...]

Подробности о том, когда следует использовать объект StringBuilder, а когда достаточно (и даже лучше) использовать конструкции вида x += y или x = x+y (x и y, естетственно, строковые или символьные переменные) замечательно изложены в статье Эффективная конкатенация строк в .NET [Копия]

Специально примера для я даже заморочился и сделал сравнительную таблицу
Метод вычисления времени выполнения взял такой же, как в статье.


PDF

Код формы тестового приложения на PasteBin
Скачать тестовое приложение с Mega.nz


Скриншот тестового приложения

Заметка в PDF

2 Responses to C#. Генерация строки из случайных символов.

  1. Я бы рекомендовал использовать не Random а класс RNGCryptoServiceProvider Class (System.Security.Cryptography) — смотреть тут https://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider(v=vs.110).aspx
    Если кратко то отличие в том что он орождает случайные байты (в массив, который можно выделить 1 раз и использовать повторно в цикле, кстати), и тогда можно сгененрировать допустим блоками по 16 байт, и по 16 символов из «алфавта» сразу.
    Тогда байты действительно будут случайные, а масштабирование на алавит можно сделать через остаток от деления на размер алвавита или вычитать из байта размер пдока не старнет меньше размера.
    Ещё можно сденерировать алфавит из 256 символов чтобы не возиться с преобразованием байта в номер буквы, «прокрутив повтором2 исходный алфавит до 256 знаков.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*