Обратите внимание, что вы НЕ должны использовать какой-либо метод, основанный на Randomклассе, для генерации паролей. Посев семян Randomимеет очень низкую энтропию, поэтому он не очень безопасен. Используйте криптографический PRNG для паролей.
CodesInChaos
2
Было бы неплохо включить языковую локализацию в этот вопрос. Особенно, если ваш графический интерфейс должен обслуживать китайский или болгарский язык!
Питер Джамменсон,
15
Что-то с таким большим количеством голосов и таким количеством качественных ответов не заслуживает того, чтобы быть отмеченным как закрытое. Я голосую за то, чтобы он был вновь открыт.
Джон Коулман
Ответы:
1686
Я слышал, что LINQ - это новый черный цвет, поэтому вот моя попытка использовать LINQ:
privatestaticRandom random =newRandom();publicstaticstringRandomString(int length){conststring chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";returnnewstring(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());}
(Примечание. Использование Randomкласса делает его непригодным для чего-либо связанного с безопасностью , например, для создания паролей или токенов. Используйте RNGCryptoServiceProviderкласс, если вам нужен сильный генератор случайных чисел.)
@Alex: Я провел несколько быстрых тестов, и кажется, что при генерации более длинных строк он масштабируется в значительной степени линейно (при условии, что на самом деле доступно достаточно памяти). Сказав это, ответ Дэн Ригби был почти в два раза быстрее, чем этот в каждом тесте.
Луки,
6
Хорошо. Если ваш критерий в том, что он использует linq и что у него паршивое повествование, то это определенно колени пчелы. Как повествование кода, так и фактический путь выполнения довольно неэффективны и косвенны. Не поймите меня неправильно, я огромный хипстер (я люблю Python), но это в значительной степени машина Руба Голдберга.
eremzeit
5
Хотя это технически отвечает на вопрос, его вывод очень вводит в заблуждение. Генерация 8 случайных символов звучит так, как будто результатов может быть очень много, тогда как в лучшем случае это дает 2 миллиарда различных результатов. А на практике еще меньше. Вы также должны добавить БОЛЬШОЕ ЖИРНОЕ предупреждение, чтобы не использовать его для каких-либо вещей, связанных с безопасностью.
CodesInChaos
41
@xaisoft: строчные буквы оставляются в качестве упражнения для читателя.
2013 г.
15
Следующая строка более эффективна по памяти (и, следовательно, по времени), чем указаннаяreturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Тайсон Уильямс
376
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";var stringChars =newchar[8];var random =newRandom();for(int i =0; i < stringChars.Length; i++){
stringChars[i]= chars[random.Next(chars.Length)];}var finalString =newString(stringChars);
Не так элегантно, как решение Linq.
(Примечание. Использование Randomкласса делает его непригодным для чего-либо связанного с безопасностью , например, для создания паролей или токенов. Используйте RNGCryptoServiceProviderкласс, если вам нужен сильный генератор случайных чисел.)
@ Алекс: Это не самый быстрый ответ, но это самый быстрый «реальный» ответ (т. Е. Из тех, которые позволяют контролировать используемые символы и длину строки).
Луки,
2
@Alex: GetRandomFileNameрешение Адама Порада быстрее, но не позволяет контролировать используемые символы, и максимально возможная длина составляет 11 символов. GuidРешение Дугласа молниеносно, но символы ограничены A-F0-9, а максимальная возможная длина составляет 32 символа.
Луки,
1
@ Адам: Да, вы можете объединить результаты нескольких вызовов, GetRandomFileNameно тогда (а) вы потеряете свое преимущество в производительности и (б) ваш код станет более сложным.
LukeH
2
@xaisoft создайте свой экземпляр объекта Random () вне вашего цикла. Если вы создадите много экземпляров Random () за короткий промежуток времени, то вызов .Next () вернет то же значение, что и Random (), использующий основанное на времени начальное число.
Дэн Ригби,
2
@xaisoft Не используйте этот ответ для чего-либо критически важного для безопасности, например для паролей. System.Randomне подходит для безопасности.
CodesInChaos
333
ОБНОВЛЕНО на основе комментариев. Исходная реализация генерировала ах ~ 1,95% времени, а оставшиеся символы - 1,56% времени. Обновление генерирует все символы ~ 1,61% времени.
ПОДДЕРЖКА РАМКИ - .NET Core 3 (и будущие платформы, поддерживающие .NET Standard 2.1 или выше) предоставляет криптографически надежный метод RandomNumberGenerator.GetInt32 () для генерации случайного целого числа в требуемом диапазоне.
В отличие от некоторых из представленных альтернатив, этот криптографически обоснован .
using System;
using System.Security.Cryptography;
using System.Text;
namespace UniqueKey{publicclassKeyGenerator{internalstaticreadonlychar[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();publicstaticstringGetUniqueKey(int size){byte[] data =newbyte[4*size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);for(int i =0; i < size; i++){var rnd =BitConverter.ToUInt32(data, i *4);var idx = rnd % chars.Length;
result.Append(chars[idx]);}return result.ToString();}publicstaticstringGetUniqueKeyOriginal_BIASED(int size){char[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();byte[] data =newbyte[size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);foreach(byte b in data){
result.Append(chars[b %(chars.Length)]);}return result.ToString();}}}
Основываясь на обсуждении альтернатив здесь и обновляется / модифицируется на основе комментариев ниже.
Вот небольшой тестовый набор, который демонстрирует распределение символов в старых и обновленных выходных данных. Для глубокого обсуждения анализа случайности , проверьте random.org.
using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;
namespace CryptoRNGDemo{classProgram{constint REPETITIONS =1000000;constint KEY_SIZE =32;staticvoidMain(string[] args){Console.WriteLine("Original BIASED implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKeyOriginal_BIASED);Console.WriteLine("Updated implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKey);Console.ReadKey();}staticvoidPerformTest(int repetitions,int keySize,Func<int,string> generator){Dictionary<char,int> counts =newDictionary<char,int>();foreach(var ch inUniqueKey.KeyGenerator.chars) counts.Add(ch,0);for(int i =0; i < REPETITIONS; i++){var key = generator(KEY_SIZE);foreach(var ch in key) counts[ch]++;}int totalChars = counts.Values.Sum();foreach(var ch inUniqueKey.KeyGenerator.chars){Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");}}}}
Это выглядит как правильный подход для меня - случайные пароли, соли, энтропия и т. Д. Не должны генерироваться с использованием Random (), который оптимизирован по скорости и генерирует воспроизводимые последовательности чисел; RNGCryptoServiceProvider.GetNonZeroBytes (), с другой стороны, создает дикие последовательности чисел, которые НЕ воспроизводимы.
mindplay.dk
25
Буквы слегка смещены (255% 62! = 0). Несмотря на этот незначительный недостаток, это, безусловно, лучшее решение здесь.
CodesInChaos
13
Обратите внимание, что это не так, если вам нужна криптостойкость, непредвзятая случайность. (А если вы этого не хотите, то зачем использовать RNGCSPв первую очередь?) Использование mod для индексации charsмассива означает, что вы получите смещенный вывод, если не chars.Lengthпроизойдет делитель 256.
LukeH
15
Одна возможность значительно уменьшить смещение - это запрос 4*maxSizeслучайных байтов, а затем использование (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. Я бы тоже использовал GetBytesвместо GetNonZeroBytes. И, наконец, вы можете удалить первый вызов GetNonZeroBytes. Вы не используете его результат.
CodesInChaos
14
Интересный факт: AZ az 0-9 - это 62 символа. Люди указывают на смещение букв, потому что 256% 62! = 0. Идентификаторы видео YouTube - это AZ az 0-9, а также «-» и «_», которые выдают 64 возможных символа, которые делятся на 256 равномерно. Стечение обстоятельств? Думаю, нет! :)
qJake,
200
Решение 1 - самый большой «диапазон» с самой гибкой длиной
Это решение имеет больший диапазон, чем использование GUID, поскольку GUID имеет пару фиксированных битов, которые всегда одинаковы и, следовательно, не случайны, например, 13 символов в шестнадцатеричном коде всегда равны «4» - по крайней мере, в GUID версии 6.
Это решение также позволяет генерировать строку любой длины.
Решение 2 - Одна строка кода - подходит для 22 символов
Вы не можете генерировать строки, пока решение 1 и строка не имеют одинаковый диапазон из-за фиксированных битов в GUID, но во многих случаях это будет работать.
Решение 3 - немного меньше кода
Guid.NewGuid().ToString("n").Substring(0,8);
В основном, это здесь для исторических целей. В нем используется немного меньше кода, хотя это и связано с меньшим диапазоном - поскольку он использует hex вместо base64, ему требуется больше символов для представления того же диапазона по сравнению с другими решениями.
Что означает больше шансов на столкновение - при тестировании с 100 000 итераций по 8 символьных строк получен один дубликат.
Вы фактически сгенерировали дубликат? Удивительно 5,316,911,983,139,663,491,615,228,241,121,400,000 возможных комбинаций GUID.
Алекс
73
@ Алекс: Он сокращает GUID до 8 символов, поэтому вероятность коллизий намного выше, чем у GUID.
DTB
23
Никто не может оценить это, кроме ботаников :) Да, вы абсолютно правы, ограничение в 8 символов имеет значение.
Алекс
31
Guid.NewGuid (). ToString ("n") сохранит тире, вызов Replace () не требуется. Но следует отметить, что GUID только 0-9 и AF. Количество комбинаций «достаточно хорошее», но нигде не близко к тому, что допускает настоящая буквенно-цифровая случайная строка. Вероятность столкновения составляет 1: 4 294 967 296 - то же самое, что и случайное 32-разрядное целое число.
ричардталлент
32
1) GUID разработаны так, чтобы быть уникальными, а не случайными. Хотя текущие версии Windows генерируют идентификаторы GUID V4, которые действительно являются случайными, это не гарантируется. Например, в более старых версиях Windows использовались идентификаторы GUID V1, в которых может произойти сбой. 2) Просто использование шестнадцатеричных символов значительно снижает качество случайной строки. От 47 до 32 бит. 3) Люди недооценивают вероятность столкновения, так как они дают ее для отдельных пар. Если вы генерируете 100k 32-битных значений, вы, вероятно, столкнетесь с одним из них. Смотрите проблему дня рождения.
CodesInChaos
72
Вот пример, который я украл у Сэма Аллена в Dot Net Perls
Если вам нужно всего 8 символов, используйте Path.GetRandomFileName () в пространстве имен System.IO. Сэм говорит, что использование «Path.GetRandomFileName метода здесь иногда лучше, потому что он использует RNGCryptoServiceProvider для лучшей случайности. Однако он ограничен 11 случайными символами».
GetRandomFileName всегда возвращает 12-символьную строку с точкой в 9-м символе. Таким образом, вам нужно удалить период (так как это не случайно), а затем взять 8 символов из строки. На самом деле, вы можете просто взять первые 8 символов и не беспокоиться о периоде.
Это хорошо работает. Я пробежал 100 000 итераций и у меня никогда не было повторяющегося имени. Тем не менее, я сделал найти несколько вульгарных слов (на английском языке). Даже не подумал бы об этом, за исключением того, что один из первых в списке имел F ***. Просто один на один, если вы используете это для чего-то, что увидит пользователь.
Techturtle
3
@techturtle Спасибо за предупреждение. Я предполагаю, что есть риск для вульгарных слов с любой случайной генерацией строки, которая использует все буквы в алфавите.
Адам Порад
красиво и просто, но не подходит для длинных струн ... проголосуй за этот хороший трюк
Махер Абутраа
Этот метод, кажется, возвращает только строчные буквенно-цифровые строки.
Джейбро
2
Время от времени бывают вульгарные слова, но если вы продолжите в том же духе, то в конце концов это напишет Шекспир. (Всего несколько жизней вселенной. :)
Слотарио,
38
Основные цели моего кода:
Распределение строк практически равномерно (не обращайте внимания на незначительные отклонения, если они небольшие)
Он выводит более нескольких миллиардов строк для каждого набора аргументов. Генерирование 8-символьной строки (~ 47 бит энтропии) не имеет смысла, если ваш PRNG генерирует только 2 миллиарда (31 бит энтропии) различных значений.
Это безопасно, так как я ожидаю, что люди будут использовать это для паролей или других токенов безопасности.
Первое свойство достигается путем принятия 64-битного значения по модулю размера алфавита. Для маленьких алфавитов (таких как 62 символа из вопроса) это приводит к незначительному смещению. Второе и третье свойство достигается использованием RNGCryptoServiceProviderвместо System.Random.
using System;
using System.Security.Cryptography;publicstaticstringGetRandomAlphanumericString(int length){conststring alphanumericCharacters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ"+"abcdefghijklmnopqrstuvwxyz"+"0123456789";returnGetRandomString(length, alphanumericCharacters);}publicstaticstringGetRandomString(int length,IEnumerable<char> characterSet){if(length <0)thrownewArgumentException("length must not be negative","length");if(length >int.MaxValue/8)// 250 million chars ought to be enough for anybodythrownewArgumentException("length is too big","length");if(characterSet ==null)thrownewArgumentNullException("characterSet");var characterArray = characterSet.Distinct().ToArray();if(characterArray.Length==0)thrownewArgumentException("characterSet must not be empty","characterSet");var bytes =newbyte[length *8];var result =newchar[length];
using (var cryptoProvider =newRNGCryptoServiceProvider()){
cryptoProvider.GetBytes(bytes);}for(int i =0; i < length; i++){ulongvalue=BitConverter.ToUInt64(bytes, i *8);
result[i]= characterArray[value%(uint)characterArray.Length];}returnnewstring(result);}
Нет пересечения с 64 x Z и Math.Pow (2, Y). Таким образом, увеличение числа уменьшает предвзятость, но не устраняет ее. Я обновил свой ответ ниже, мой подход состоял в том, чтобы отбросить случайные входные данные и заменить их на другое значение.
Тодд
@ Тодд Я знаю, что это не устраняет смещение, но я выбрал простоту этого решения вместо устранения практически несущественного смещения.
CodesInChaos
Я согласен, что в большинстве случаев это практически не имеет значения. Но теперь я обновил мой, чтобы быть таким же быстрым, как Random, и немного более безопасным, чем ваш. Все с открытым исходным кодом для всех, чтобы поделиться. Да, я потратил слишком много времени на это ...
Тодд
Если мы используем провайдера RNG, есть ли у нас какой-либо способ избежать систематической ошибки? Я не уверен ... Если Тодд имеет в виду способ, когда он генерирует дополнительное случайное число (когда мы находимся в зоне смещения), то это может быть ошибочным предположением. ГСЧ имеет практически линейное распределение всех генерируемых значений в среднем. Но это не значит, что у нас не будет локальной корреляции между генерируемыми байтами. Таким образом, дополнительный байт только для зоны смещения может дать нам некоторый уклон, но по другой причине. Скорее всего, это смещение будет очень маленьким. НО в этом случае увеличение общего количества сгенерированных байтов является более простым способом.
Максим
1
@Maxim Вы можете использовать отклонение, чтобы полностью устранить смещение (при условии, что базовый генератор является совершенно случайным). Взамен код может выполняться произвольно долго (с экспоненциально малой вероятностью).
Если вы когда-нибудь беспокоитесь, что английские алфавиты могут когда-нибудь измениться, и вы можете потерять бизнес, тогда вы можете избежать жесткого кодирования, но должны работать немного хуже (сравнимо с Path.GetRandomFileNameподходом)
publicstaticstringGetRandomAlphaNumeric(){var chars ='a'.To('z').Concat('0'.To('9')).ToList();returnnewstring(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());}publicstaticIEnumerable<char>To(thischar start,char end){if(end < start)thrownewArgumentOutOfRangeException("the end char should not be less than start char", innerException:null);returnEnumerable.Range(start, end - start +1).Select(i =>(char)i);}
Последние два подхода выглядят лучше, если вы можете сделать их методом расширения в System.Randomэкземпляре.
Использование chars.Selectочень уродливо, так как оно зависит от размера выходного файла, не превышающего размер алфавита.
CodesInChaos
@CodesInChaos Я не уверен, что понимаю вас. Вы имеете в виду в 'a'.To('z')подходе?
nawfal
1
1) chars.Select().Take (n) `работает только если chars.Count >= n. Выбор последовательности, которую вы на самом деле не используете, немного не интуитивен, особенно с этим неявным ограничением длины. Я бы лучше использовал Enumerable.Rangeили Enumerable.Repeat. 2) Сообщение об ошибке «конечный символ должен быть меньше начального символа» является неправильным путем / отсутствует a not.
CodesInChaos
@CodesInChaos, но в моем случае chars.Countэто путь > n. Также я не понимаю неинтуитивную часть. Что делает все использует Takeнеинтуитивным не так ли? Я не верю в это. Спасибо за указание на опечатку.
Проверено в LinqPad. Для строки размером 10 генерирует:
из Linq = chdgmevhcy [10]
из цикла = gtnoaryhxr [10]
из Select = rsndbztyby [10]
из GenerateRandomString = owyefjjakj [10]
от SecureFastRandom = VzougLYHYP [10]
от SecureFastRandom-NoCache = oVQXNGmO1S [10]
И показатели производительности, как правило, меняются незначительно, очень редко NonOptimizedна самом деле быстрее, а иногда ForLoopи GenerateRandomStringпереключают, кто лидирует.
LinqIsTheNewBlack (10000x) = 96762 тиков прошло (9,6762 мс)
Было бы интересно узнать, какие из них создали дуплики.
Ребекка
@Junto - чтобы выяснить, что приводит к дубликатам, что-то вроде того var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());, где вы заменяете EachRandomizingMethod... каждый метод
Я думал об этом, но не смог избавиться от буквенно-цифровых символов, поскольку 2-й аргумент - это МИНИМАЛЬНЫЕ не буквенные символы
ozzy432836
13
Код, написанный Эриком Дж., Довольно неряшливый (совершенно очевидно, что он написан 6 лет назад ... он, вероятно, не написал бы этот код сегодня), и есть даже некоторые проблемы.
В отличие от некоторых из представленных альтернатив, этот криптографически обоснован.
Неверно ... Существует смещение в пароле (как написано в комментарии), bcdefghнемного более вероятно, чем другие ( aне потому, что GetNonZeroBytesон не генерирует байты со значением ноль, поэтому смещение дляa уравновешивается его), так что это на самом деле не криптографически звук.
Это должно исправить все проблемы.
publicstaticstringGetUniqueKey(int size =6,string chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"){
using (var crypto =newRNGCryptoServiceProvider()){var data =newbyte[size];// If chars.Length isn't a power of 2 then there is a bias if// we simply use the modulus operator. The first characters of// chars will be more probable than the last ones.// buffer used if we encounter an unusable random byte. We will// regenerate it in this bufferbyte[] smallBuffer =null;// Maximum random number that can be used without introducing a// biasint maxRandom =byte.MaxValue-((byte.MaxValue+1)% chars.Length);
crypto.GetBytes(data);var result =newchar[size];for(int i =0; i < size; i++){byte v = data[i];while(v > maxRandom){if(smallBuffer ==null){
smallBuffer =newbyte[1];}
crypto.GetBytes(smallBuffer);
v = smallBuffer[0];}
result[i]= chars[v % chars.Length];}returnnewstring(result);}}
Мы также используем произвольную строку произвольно, но мы реализовали ее как вспомогательный метод строки, поэтому она обеспечивает некоторую гибкость ...
publicstaticstringRandom(thisstring chars,int length =8){var randomString =newStringBuilder();var random =newRandom();for(int i =0; i < length; i++)
randomString.Append(chars[random.Next(chars.Length)]);return randomString.ToString();}
Применение
var random ="ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();
или
var random ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16);
Вопрос: Почему я должен тратить свое время, используя Enumerable.Rangeвместо ввода "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"?
using System;
using System.Collections.Generic;
using System.Linq;publicclassTest{publicstaticvoidMain(){var randomCharacters =GetRandomCharacters(8,true);Console.WriteLine(newstring(randomCharacters.ToArray()));}privatestaticList<char> getAvailableRandomCharacters(bool includeLowerCase){var integers =Enumerable.Empty<int>();
integers = integers.Concat(Enumerable.Range('A',26));
integers = integers.Concat(Enumerable.Range('0',10));if( includeLowerCase )
integers = integers.Concat(Enumerable.Range('a',26));return integers.Select(i =>(char)i).ToList();}publicstaticIEnumerable<char>GetRandomCharacters(int count,bool includeLowerCase){var characters = getAvailableRandomCharacters(includeLowerCase);var random =newRandom();var result =Enumerable.Range(0, count).Select(_ => characters[random.Next(characters.Count)]);return result;}}
Ответ: Волшебные струны ПЛОХО. Кто-нибудь заметил, что не было "I в моей строке вверху "? Моя мама научила меня не использовать магические струны именно по этой причине ...
nb 1: как говорили многие другие, такие как @dtb, не используйте, System.Randomесли вам нужна криптографическая защита ...
Примечание 2: Этот ответ не самый эффективный или самый короткий, но я хотел, чтобы место отделяло ответ от вопроса. Цель моего ответа - больше предостеречь от волшебных строк, чем дать причудливый инновационный ответ.
Буквенно-цифровой (без учета регистра) есть [A-Z0-9]. Если, случайно, ваша случайная строка только когда-либо покрывает [A-HJ-Z0-9]результат, не покрывает весь допустимый диапазон, что может быть проблематично.
Вай Ха Ли
Как это было бы проблематично? Так что не содержит I. Это потому, что на одного персонажа меньше, и его легче взломать? Какова статистика взламываемых паролей, которые содержат 35 символов в диапазоне, а не 36. Я думаю, что я скорее рискну ... или просто проверю тростниковый диапазон символов ... чем включу весь этот дополнительный мусор в мой код. Но это я. Я имею в виду, чтобы не быть прикладом, я просто говорю. Иногда я думаю, что программисты склонны идти по сверхсложному пути ради того, чтобы быть слишком сложным.
Кристина
1
Это зависит от варианта использования. Очень часто исключают такие символы, как Iи Oиз этих типов случайных строк, чтобы люди не путали их с 1и 0. Если вас не волнует наличие удобочитаемой строки, хорошо, но если это то, что кому-то может понадобиться напечатать, то на самом деле разумно удалить эти символы.
Крис Пратт
5
Немного более чистая версия решения DTB.
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";var random =newRandom();varlist=Enumerable.Repeat(0,8).Select(x=>chars[random.Next(chars.Length)]);returnstring.Join("",list);
Изучив другие ответы и рассмотрев комментарии CodeInChaos, наряду с CodeInChaos, все еще предвзятым (хотя и менее) ответом, я подумал, что необходимо окончательное окончательное решение . Поэтому, обновляя свой ответ, я решил сделать все возможное.
Относительно некоторых других ответов - если вы знаете длину вывода, вам не нужен StringBuilder, и при использовании ToCharArray это создает и заполняет массив (вам не нужно сначала создавать пустой массив)
Относительно некоторых других ответов - Вы должны использовать NextBytes, а не получать по одному для производительности
Технически вы можете закрепить байтовый массив для более быстрого доступа. Обычно это стоит того, чтобы выполнить итерацию более 6-8 раз по байтовому массиву. (Не сделано здесь)
Использование RNGCryptoServiceProvider для лучшей случайности
Использование кэширования буфера случайных данных объемом 1 МБ. Сравнительный анализ показывает, что скорость доступа к кэшированным однобайтовым файлам составляет ~ 1000 раз быстрее - 9 мкс за 1 МБ против 989 мс для не кэшированных.
Оптимизировано отклонение зоны смещения в моем новом классе.
Конец решения вопроса:
staticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];SecureFastRandom.GetNextBytesMax(rBytes, biasZone);for(var i =0; i <Length; i++){
rName[i]= charSet[rBytes[i]% charSet.Length];}returnnewstring(rName);}
Но вам нужен мой новый (непроверенный) класс:
/// <summary>/// My benchmarking showed that for RNGCryptoServiceProvider:/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference /// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached/// </summary>classSecureFastRandom{staticbyte[] byteCache =newbyte[1000000];//My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)staticint lastPosition =0;staticint remaining =0;/// <summary>/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function/// </summary>/// <param name="buffer"></param>publicstaticvoidDirectGetBytes(byte[] buffer){
using (var r =newRNGCryptoServiceProvider()){
r.GetBytes(buffer);}}/// <summary>/// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance/// </summary>/// <param name="buffer"></param>publicstaticvoidGetBytes(byte[] buffer){if(buffer.Length> byteCache.Length){DirectGetBytes(buffer);return;}lock(byteCache){if(buffer.Length> remaining){DirectGetBytes(byteCache);
lastPosition =0;
remaining = byteCache.Length;}Buffer.BlockCopy(byteCache, lastPosition, buffer,0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;}}/// <summary>/// Return a single byte from the cache of random data./// </summary>/// <returns></returns>publicstaticbyteGetByte(){lock(byteCache){returnUnsafeGetByte();}}/// <summary>/// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache./// </summary>/// <returns></returns>staticbyteUnsafeGetByte(){if(1> remaining){DirectGetBytes(byteCache);
lastPosition =0;
remaining = byteCache.Length;}
lastPosition++;
remaining--;return byteCache[lastPosition -1];}/// <summary>/// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number./// </summary>/// <param name="buffer"></param>/// <param name="max"></param>publicstaticvoidGetBytesWithMax(byte[] buffer,byte max){if(buffer.Length> byteCache.Length/2)//No point caching for larger sizes{DirectGetBytes(buffer);lock(byteCache){UnsafeCheckBytesMax(buffer, max);}}else{lock(byteCache){if(buffer.Length> remaining)//Recache if not enough remaining, discarding remaining - too much work to join two blocksDirectGetBytes(byteCache);Buffer.BlockCopy(byteCache, lastPosition, buffer,0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;UnsafeCheckBytesMax(buffer, max);}}}/// <summary>/// Checks buffer for bytes equal and above max. Must be called within lock of byteCache./// </summary>/// <param name="buffer"></param>/// <param name="max"></param>staticvoidUnsafeCheckBytesMax(byte[] buffer,byte max){for(int i =0; i < buffer.Length; i++){while(buffer[i]>= max)
buffer[i]=UnsafeGetByte();//Replace all bytes which are equal or above max}}}
Для истории - мое старое решение для этого ответа, использовало случайный объект:
privatestaticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();static rGen =newRandom();//Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);staticboolSlightlyMoreSecurityNeeded=true;//Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];lock(rGen)//~20-50ns{
rGen.NextBytes(rBytes);for(int i =0; i <Length; i++){while(SlightlyMoreSecurityNeeded&& rBytes[i]>= biasZone)//Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
rBytes[i]= rGen.NextByte();
rName[i]= charSet[rBytes[i]% charSet.Length];}}returnnewstring(rName);}
Представление:
SecureFastRandom - первый одиночный запуск = ~ 9-33мс . Незаметный. Постоянно : 5 мс (иногда до 13 мс) в течение 10 000 итераций, с одной средней итерацией = 1,5 микросекунды. , Примечание: обычно требуется 2, но иногда до 8 обновлений кэша - зависит от того, сколько отдельных байтов превышает зону смещения
Случайный - Первый одиночный прогон = ~ 0-1мс . Незаметный. Постоянно : 5 мс, более 10000 итераций. С одной средней итерацией = .5 микросекунд. , Примерно с той же скоростью.
Эти ссылки являются еще одним подходом. Буферизацию можно было бы добавить к этой новой кодовой базе, но самым важным было изучение различных подходов к устранению смещения и сравнительный анализ скоростей и плюсов / минусов.
Я обнаружил некоторые незначительные улучшения производительности вашего метода, которые, похоже, были
излишними
5
1) Почему все эти магические константы? Вы указали длину вывода три раза. Просто определите его как константу или параметр. Вы можете использовать charSet.Lengthвместо 62. 2) RandomСтатика без блокировки означает, что этот код не является потокобезопасным. 3) уменьшение 0-255 мод 62 вводит обнаруживаемое смещение. 4) Вы не можете использовать ToStringмассив символов, который всегда возвращается "System.Char[]". Вы должны использовать new String(rName)вместо этого.
CodesInChaos
Спасибо @CodesInChaos, я никогда не думал об этих вещах тогда. Все еще только с использованием класса Random, но это должно быть лучше. Я не мог придумать лучшего способа обнаружения и исправления смещений.
Тодд
Немного глупо начинать со слабого RNG ( System.Random), а затем осторожно избегать любых ошибок в вашем собственном коде. На ум приходит выражение «полировка какашки».
CodesInChaos
@CodesInChaos И теперь ученик превзошел своего хозяина
Тодд
4
Ужасно, я знаю, но я просто не мог с собой поделать:
namespace ConsoleApplication2{
using System;
using System.Text.RegularExpressions;classProgram{staticvoidMain(string[] args){Random adomRng =newRandom();string rndString =string.Empty;char c;for(int i =0; i <8; i++){while(!Regex.IsMatch((c=Convert.ToChar(adomRng.Next(48,128))).ToString(),"[A-Za-z0-9]"));
rndString += c;}Console.WriteLine(rndString +Environment.NewLine);}}}
Я искал более конкретный ответ, где хочу контролировать формат случайной строки и наткнулся на этот пост. Например: номерные знаки (автомобилей) имеют определенный формат (для каждой страны), и я хотел создать случайные номерные знаки.
Я решил написать свой собственный метод расширения Random для этого. (это делается для того, чтобы повторно использовать один и тот же объект Random, так как в сценариях с многопоточностью вы можете получить двойные значения). Я создал гист ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), но также скопирую здесь класс расширения:
voidMain(){Random rnd =newRandom();
rnd.GetString("1-###-000").Dump();}publicstaticclassRandomExtensions{publicstaticstringGetString(thisRandom random,string format){// Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c// Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)StringBuilder result =newStringBuilder();for(int formatIndex =0; formatIndex < format.Length; formatIndex++){switch(format.ToUpper()[formatIndex]){case'0': result.Append(getRandomNumeric(random));break;case'#': result.Append(getRandomCharacter(random));break;default: result.Append(format[formatIndex]);break;}}return result.ToString();}privatestaticchar getRandomCharacter(Random random){string chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";return chars[random.Next(chars.Length)];}privatestaticchar getRandomNumeric(Random random){string nums ="0123456789";return nums[random.Next(nums.Length)];}}
Использование свойства для чего-то, что изменяется при каждом доступе, довольно сомнительно. Я бы рекомендовал вместо этого использовать метод.
CodesInChaos
2
RNGCryptoServiceProviderследует утилизировать после использования.
Цахи Ашер
Я исправил проблему IDisposable, но это все еще очень сомнительно, создавая новый RNGCryptoServiceProvider для каждого письма.
piojo
@CodesInChaos сделано, теперь метод.
Матас Вайткявичюс
3
Попробуйте объединить две части: уникальную (последовательность, счетчик или дата) и случайную
publicclassRandomStringGenerator{publicstaticstringGen(){returnConvertToBase(DateTime.UtcNow.ToFileTimeUtc())+GenRandomStrings(5);//keep length fixed at least of one part}privatestaticstringGenRandomStrings(int strLen){var result =string.Empty;varGen=newRNGCryptoServiceProvider();var data =newbyte[1];while(result.Length< strLen){Gen.GetNonZeroBytes(data);int code = data[0];if(code >48&& code <57||// 0-9
code >65&& code <90||// A-Z
code >97&& code <122// a-z){
result +=Convert.ToChar(code);}}return result;}privatestaticstringConvertToBase(long num,int nbase =36){var chars ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//if you wish make algorithm more secure - change order of letter here// check if we can convert to another baseif(nbase <2|| nbase > chars.Length)returnnull;int r;var newNumber =string.Empty;// in r we have the offset of the char that was converted to the new basewhile(num >= nbase){
r =(int)(num % nbase);
newNumber = chars[r]+ newNumber;
num = num / nbase;}// the last number to convert
newNumber = chars[(int)num]+ newNumber;return newNumber;}}
1) Вы можете использовать символьные литералы вместо значений ASCII, связанных с этими символами. 2) В коде совпадения интервалов возникла ошибка «один за другим». Вам нужно использовать <=и >=вместо <и >. 3) Я бы добавил ненужные скобки вокруг &&выражений, чтобы было ясно, что они имеют приоритет, но, конечно, это только стилистический выбор.
CodesInChaos
+1 Хорошо для устранения смещения и добавления тестирования. Я не уверен, почему вы добавляете вашу случайную строку к строке, полученной из отметки времени? Кроме того, вам все еще нужно избавиться от вашего RNGCryptoServiceProvider
monty
2
Решение без использования Random:
var chars =Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",8);var randomStr =newstring(chars.SelectMany(str => str).OrderBy(c =>Guid.NewGuid()).Take(8).ToArray());
NewGuid использует случайное внутреннее. Так что это все еще использует случайное, это просто скрывает это.
Клин
2
Вот вариант решения Eric J, то есть криптографически обоснованный, для WinRT (приложение для Магазина Windows):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newStringBuilder(length);for(int i =0; i < length;++i){
result.Append(CryptographicBuffer.GenerateRandomNumber()% chars.Length);}return result.ToString();}
Если производительность имеет значение (особенно при большой длине):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newSystem.Text.StringBuilder(length);var bytes =CryptographicBuffer.GenerateRandom((uint)length *4).ToArray();for(int i =0; i < bytes.Length; i +=4){
result.Append(BitConverter.ToUInt32(bytes, i)% chars.Length);}return result.ToString();}
Это не криптографически обоснованно. Существует небольшой уклон из-за операции модуля, не распространяющей всю ширину ulong в равной степени на 62 символа.
Ли Райан
1
Я знаю, что это не лучший способ. Но вы можете попробовать это.
string str =Path.GetRandomFileName();//This method returns a random file name of 11 characters
str = str.Replace(".","");Console.WriteLine("Random string: "+ str);
Как эта линия? Console.WriteLine ($ "Случайная строка: {Path.GetRandomFileName (). Replace (". "," ")}"); это одна строка.
PmanAce
1
Я не знаю, насколько криптографически это звучит, но он более читабелен и лаконичен, чем более сложные решения (imo), и должен быть более «случайным», чем System.Randomрешения на основе.
Конечно, он не оптимизирован по скорости, поэтому, если критически важно генерировать миллионы случайных строк каждую секунду, попробуйте другую!
ПРИМЕЧАНИЕ. Это решение не допускает повторения символов в алфавите, и алфавит ДОЛЖЕН иметь такой же или больший размер, чем выходная строка, что делает этот подход менее желательным в некоторых обстоятельствах, все зависит от вашего варианта использования.
Если ваши значения не являются полностью случайными, но на самом деле могут зависеть от чего-то - вы можете вычислить хэш md5 или sha1 для этого 'somwthing', а затем обрезать его до любой желаемой длины.
1) статические методы должны быть потокобезопасными. 2) Какой смысл увеличивать индекс, а не использовать результат random.Nextнапрямую? Усложняет код и не дает ничего полезного.
CodesInChaos
0
Вот механизм для генерации случайной буквенно-цифровой строки (я использую это для генерации паролей и тестовых данных) без определения алфавита и цифр,
CleanupBase64 удалит необходимые части в строке и будет рекурсивно добавлять случайные буквенно-цифровые буквы.
publicstaticstringGenerateRandomString(int length){var numArray =newbyte[length];newRNGCryptoServiceProvider().GetBytes(numArray);returnCleanUpBase64String(Convert.ToBase64String(numArray), length);}privatestaticstringCleanUpBase64String(string input,int maxLength){
input = input.Replace("-","");
input = input.Replace("=","");
input = input.Replace("/","");
input = input.Replace("+","");
input = input.Replace(" ","");while(input.Length< maxLength)
input = input +GenerateRandomString(maxLength);return input.Length<= maxLength ?
input.ToUpper()://In my case I want capital letters
input.ToUpper().Substring(0, maxLength);}
Вы объявили GenerateRandomStringи позвонили GetRandomStringизнутри SanitiseBase64String. Кроме того, вы заявили , SanitiseBase64String и вызов CleanUpBase64Stringв GenerateRandomString.
Вай Ха Ли
0
Есть один из удивительных пакетов nuget, которые делают это так просто.
var myObject =newFaker<MyObject>().RuleFor(p => p.MyAlphaNumericProperty, f => f.Random.AlphaNumeric(/*lenght*/7)).Generate();
не уверен на 100%, так как я не проверял здесь КАЖДЫЙ вариант, но из тех, что я тестировал, этот самый быстрый. рассчитал время с секундомером, и он показал 9-10 тиков, поэтому, если скорость важнее безопасности, попробуйте это:
privatestaticRandom random =newRandom();publicstaticstringRandom(int length){var stringChars =newchar[length];for(int i =0; i < length; i++){
stringChars[i]=(char)random.Next(0x30,0x7a);returnnewstring(stringChars);}}
Random
классе, для генерации паролей. Посев семянRandom
имеет очень низкую энтропию, поэтому он не очень безопасен. Используйте криптографический PRNG для паролей.Ответы:
Я слышал, что LINQ - это новый черный цвет, поэтому вот моя попытка использовать LINQ:
(Примечание. Использование
Random
класса делает его непригодным для чего-либо связанного с безопасностью , например, для создания паролей или токенов. ИспользуйтеRNGCryptoServiceProvider
класс, если вам нужен сильный генератор случайных чисел.)источник
return new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Не так элегантно, как решение Linq.
(Примечание. Использование
Random
класса делает его непригодным для чего-либо связанного с безопасностью , например, для создания паролей или токенов. ИспользуйтеRNGCryptoServiceProvider
класс, если вам нужен сильный генератор случайных чисел.)источник
GetRandomFileName
решение Адама Порада быстрее, но не позволяет контролировать используемые символы, и максимально возможная длина составляет 11 символов.Guid
Решение Дугласа молниеносно, но символы ограничены A-F0-9, а максимальная возможная длина составляет 32 символа.GetRandomFileName
но тогда (а) вы потеряете свое преимущество в производительности и (б) ваш код станет более сложным.System.Random
не подходит для безопасности.В отличие от некоторых из представленных альтернатив, этот криптографически обоснован .
Основываясь на обсуждении альтернатив здесь и обновляется / модифицируется на основе комментариев ниже.
Вот небольшой тестовый набор, который демонстрирует распределение символов в старых и обновленных выходных данных. Для глубокого обсуждения анализа случайности , проверьте random.org.
источник
RNGCSP
в первую очередь?) Использование mod для индексацииchars
массива означает, что вы получите смещенный вывод, если неchars.Length
произойдет делитель 256.4*maxSize
случайных байтов, а затем использование(UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length
. Я бы тоже использовалGetBytes
вместоGetNonZeroBytes
. И, наконец, вы можете удалить первый вызовGetNonZeroBytes
. Вы не используете его результат.Решение 1 - самый большой «диапазон» с самой гибкой длиной
Это решение имеет больший диапазон, чем использование GUID, поскольку GUID имеет пару фиксированных битов, которые всегда одинаковы и, следовательно, не случайны, например, 13 символов в шестнадцатеричном коде всегда равны «4» - по крайней мере, в GUID версии 6.
Это решение также позволяет генерировать строку любой длины.
Решение 2 - Одна строка кода - подходит для 22 символов
Вы не можете генерировать строки, пока решение 1 и строка не имеют одинаковый диапазон из-за фиксированных битов в GUID, но во многих случаях это будет работать.
Решение 3 - немного меньше кода
В основном, это здесь для исторических целей. В нем используется немного меньше кода, хотя это и связано с меньшим диапазоном - поскольку он использует hex вместо base64, ему требуется больше символов для представления того же диапазона по сравнению с другими решениями.
Что означает больше шансов на столкновение - при тестировании с 100 000 итераций по 8 символьных строк получен один дубликат.
источник
Вот пример, который я украл у Сэма Аллена в Dot Net Perls
Если вам нужно всего 8 символов, используйте Path.GetRandomFileName () в пространстве имен System.IO. Сэм говорит, что использование «Path.GetRandomFileName метода здесь иногда лучше, потому что он использует RNGCryptoServiceProvider для лучшей случайности. Однако он ограничен 11 случайными символами».
GetRandomFileName всегда возвращает 12-символьную строку с точкой в 9-м символе. Таким образом, вам нужно удалить период (так как это не случайно), а затем взять 8 символов из строки. На самом деле, вы можете просто взять первые 8 символов и не беспокоиться о периоде.
PS: спасибо Сэм
источник
Основные цели моего кода:
Первое свойство достигается путем принятия 64-битного значения по модулю размера алфавита. Для маленьких алфавитов (таких как 62 символа из вопроса) это приводит к незначительному смещению. Второе и третье свойство достигается использованием
RNGCryptoServiceProvider
вместоSystem.Random
.источник
Простейший:
Вы можете получить лучшую производительность, если жестко закодировать массив char и положиться на
System.Random
:Если вы когда-нибудь беспокоитесь, что английские алфавиты могут когда-нибудь измениться, и вы можете потерять бизнес, тогда вы можете избежать жесткого кодирования, но должны работать немного хуже (сравнимо с
Path.GetRandomFileName
подходом)Последние два подхода выглядят лучше, если вы можете сделать их методом расширения в
System.Random
экземпляре.источник
chars.Select
очень уродливо, так как оно зависит от размера выходного файла, не превышающего размер алфавита.'a'.To('z')
подходе?chars.Select()
.Take (n) `работает только еслиchars.Count >= n
. Выбор последовательности, которую вы на самом деле не используете, немного не интуитивен, особенно с этим неявным ограничением длины. Я бы лучше использовалEnumerable.Range
илиEnumerable.Repeat
. 2) Сообщение об ошибке «конечный символ должен быть меньше начального символа» является неправильным путем / отсутствует anot
.chars.Count
это путь> n
. Также я не понимаю неинтуитивную часть. Что делает все используетTake
неинтуитивным не так ли? Я не верю в это. Спасибо за указание на опечатку.Просто сравнение производительности различных ответов в этой теме:
Методы и настройка
Результаты
Проверено в LinqPad. Для строки размером 10 генерирует:
И показатели производительности, как правило, меняются незначительно, очень редко
NonOptimized
на самом деле быстрее, а иногдаForLoop
иGenerateRandomString
переключают, кто лидирует.источник
var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());
, где вы заменяетеEachRandomizingMethod
... каждый методОдна строка кода
Membership.GeneratePassword()
делает свое дело :)Вот демо для того же.
источник
Код, написанный Эриком Дж., Довольно неряшливый (совершенно очевидно, что он написан 6 лет назад ... он, вероятно, не написал бы этот код сегодня), и есть даже некоторые проблемы.
Неверно ... Существует смещение в пароле (как написано в комментарии),
bcdefgh
немного более вероятно, чем другие (a
не потому, чтоGetNonZeroBytes
он не генерирует байты со значением ноль, поэтому смещение дляa
уравновешивается его), так что это на самом деле не криптографически звук.Это должно исправить все проблемы.
источник
Мы также используем произвольную строку произвольно, но мы реализовали ее как вспомогательный метод строки, поэтому она обеспечивает некоторую гибкость ...
Применение
или
источник
Мой простой однострочный код работает на меня :)
Чтобы расширить это для любой длины строки
источник
Другим вариантом может быть использование Linq и агрегирование случайных символов в строителе строк.
источник
Вопрос: Почему я должен тратить свое время, используя
Enumerable.Range
вместо ввода"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"
?Ответ: Волшебные струны ПЛОХО. Кто-нибудь заметил, что не было "
I
в моей строке вверху "? Моя мама научила меня не использовать магические струны именно по этой причине ...nb 1: как говорили многие другие, такие как @dtb, не используйте,
System.Random
если вам нужна криптографическая защита ...Примечание 2: Этот ответ не самый эффективный или самый короткий, но я хотел, чтобы место отделяло ответ от вопроса. Цель моего ответа - больше предостеречь от волшебных строк, чем дать причудливый инновационный ответ.
источник
I
?"[A-Z0-9]
. Если, случайно, ваша случайная строка только когда-либо покрывает[A-HJ-Z0-9]
результат, не покрывает весь допустимый диапазон, что может быть проблематично.I
. Это потому, что на одного персонажа меньше, и его легче взломать? Какова статистика взламываемых паролей, которые содержат 35 символов в диапазоне, а не 36. Я думаю, что я скорее рискну ... или просто проверю тростниковый диапазон символов ... чем включу весь этот дополнительный мусор в мой код. Но это я. Я имею в виду, чтобы не быть прикладом, я просто говорю. Иногда я думаю, что программисты склонны идти по сверхсложному пути ради того, чтобы быть слишком сложным.I
иO
из этих типов случайных строк, чтобы люди не путали их с1
и0
. Если вас не волнует наличие удобочитаемой строки, хорошо, но если это то, что кому-то может понадобиться напечатать, то на самом деле разумно удалить эти символы.Немного более чистая версия решения DTB.
Ваши предпочтения стиля могут отличаться.
источник
источник
Изучив другие ответы и рассмотрев комментарии CodeInChaos, наряду с CodeInChaos, все еще предвзятым (хотя и менее) ответом, я подумал, что необходимо окончательное окончательное решение . Поэтому, обновляя свой ответ, я решил сделать все возможное.
Чтобы получить актуальную версию этого кода, посетите новый репозиторий Hg в Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Я рекомендую вам скопировать и вставить код из: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.csfatfidfdedededededededededededede (убедитесь , что вы выберите кнопка Raw, чтобы было проще копировать и убедиться, что у вас установлена последняя версия, я думаю, что эта ссылка ведет на конкретную версию кода, а не на последнюю).
Обновленные заметки:
Конец решения вопроса:
Но вам нужен мой новый (непроверенный) класс:
Для истории - мое старое решение для этого ответа, использовало случайный объект:
Представление:
Также проверьте:
Эти ссылки являются еще одним подходом. Буферизацию можно было бы добавить к этой новой кодовой базе, но самым важным было изучение различных подходов к устранению смещения и сравнительный анализ скоростей и плюсов / минусов.
источник
charSet.Length
вместо62
. 2)Random
Статика без блокировки означает, что этот код не является потокобезопасным. 3) уменьшение 0-255 мод 62 вводит обнаруживаемое смещение. 4) Вы не можете использоватьToString
массив символов, который всегда возвращается"System.Char[]"
. Вы должны использоватьnew String(rName)
вместо этого.System.Random
), а затем осторожно избегать любых ошибок в вашем собственном коде. На ум приходит выражение «полировка какашки».Ужасно, я знаю, но я просто не мог с собой поделать:
источник
Я искал более конкретный ответ, где хочу контролировать формат случайной строки и наткнулся на этот пост. Например: номерные знаки (автомобилей) имеют определенный формат (для каждой страны), и я хотел создать случайные номерные знаки.
Я решил написать свой собственный метод расширения Random для этого. (это делается для того, чтобы повторно использовать один и тот же объект Random, так как в сценариях с многопоточностью вы можете получить двойные значения). Я создал гист ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), но также скопирую здесь класс расширения:
источник
Теперь в однострочном аромате.
источник
RNGCryptoServiceProvider
следует утилизировать после использования.Попробуйте объединить две части: уникальную (последовательность, счетчик или дата) и случайную
тесты:
источник
<=
и>=
вместо<
и>
. 3) Я бы добавил ненужные скобки вокруг&&
выражений, чтобы было ясно, что они имеют приоритет, но, конечно, это только стилистический выбор.Решение без использования
Random
:источник
Вот вариант решения Eric J, то есть криптографически обоснованный, для WinRT (приложение для Магазина Windows):
Если производительность имеет значение (особенно при большой длине):
источник
Я знаю, что это не лучший способ. Но вы можете попробовать это.
источник
Я не знаю, насколько криптографически это звучит, но он более читабелен и лаконичен, чем более сложные решения (imo), и должен быть более «случайным», чем
System.Random
решения на основе.Я не могу решить, считаю ли я эту версию или следующую «более симпатичной», но они дают точно такие же результаты:
Конечно, он не оптимизирован по скорости, поэтому, если критически важно генерировать миллионы случайных строк каждую секунду, попробуйте другую!
ПРИМЕЧАНИЕ. Это решение не допускает повторения символов в алфавите, и алфавит ДОЛЖЕН иметь такой же или больший размер, чем выходная строка, что делает этот подход менее желательным в некоторых обстоятельствах, все зависит от вашего варианта использования.
источник
Если ваши значения не являются полностью случайными, но на самом деле могут зависеть от чего-то - вы можете вычислить хэш md5 или sha1 для этого 'somwthing', а затем обрезать его до любой желаемой длины.
Также вы можете генерировать и усекать guid.
источник
источник
random.Next
напрямую? Усложняет код и не дает ничего полезного.Вот механизм для генерации случайной буквенно-цифровой строки (я использую это для генерации паролей и тестовых данных) без определения алфавита и цифр,
CleanupBase64 удалит необходимые части в строке и будет рекурсивно добавлять случайные буквенно-цифровые буквы.
источник
GenerateRandomString
и позвонилиGetRandomString
изнутриSanitiseBase64String
. Кроме того, вы заявили ,SanitiseBase64String
и вызовCleanUpBase64String
вGenerateRandomString
.Есть один из удивительных пакетов nuget, которые делают это так просто.
Один из хороших примеров здесь .
источник
не уверен на 100%, так как я не проверял здесь КАЖДЫЙ вариант, но из тех, что я тестировал, этот самый быстрый. рассчитал время с секундомером, и он показал 9-10 тиков, поэтому, если скорость важнее безопасности, попробуйте это:
источник