Как я могу генерировать случайные буквенно-цифровые строки в C#? [закрытый]
Как я могу генерировать случайные 8-символьные буквенно-цифровые строки в C#?
30 ответов
Я слышал, что LINQ-это новый черный, поэтому вот моя попытка использовать LINQ:
private static Random random = new Random();
public static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
(Примечание: использование случайного класса делает это не подходит для чего-либо, связанного с безопасностью, например, создание паролей или токенов. Используйте класс RNGCryptoServiceProvider если вам нужен сильный генератор случайных чисел.)
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[8];
var random = new Random();
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
не так элегантно, как решение Linq. (-:
(Примечание: использование случайного класса делает это не подходит для чего-либо, связанного с безопасностью, например, создание паролей или токенов. Используйте класс RNGCryptoServiceProvider если вам нужен сильный генератор случайных чисел.)
эта реализация (найденная через google) выглядит для меня звуковой.
В отличие от некоторых представленных альтернатив, это звук криптографически.
using System.Security.Cryptography;
using System.Text;
namespace UniqueKey
{
public class KeyGenerator
{
public static string GetUniqueKey(int maxSize)
{
char[] chars = new char[62];
chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
byte[] data = new byte[1];
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetNonZeroBytes(data);
data = new byte[maxSize];
crypto.GetNonZeroBytes(data);
}
StringBuilder result = new StringBuilder(maxSize);
foreach (byte b in data)
{
result.Append(chars[b % (chars.Length)]);
}
return result.ToString();
}
}
}
выбрал это из обсуждения альтернатив здесь
Решение 1-самый большой "диапазон" с самой гибкой длиной
string get_unique_string(int string_length) {
using(var rng = new RNGCryptoServiceProvider()) {
var bit_count = (string_length * 6);
var byte_count = ((bit_count + 7) / 8); // rounded up
var bytes = new byte[byte_count];
rng.GetBytes(bytes);
return Convert.ToBase64String(bytes);
}
}
это решение имеет больший диапазон, чем использование GUID, потому что GUID имеет пару фиксированных битов, которые всегда одинаковы и, следовательно, не случайны, например, 13 символов в hex всегда "4" - по крайней мере, в версии 6 GUID.
Это решение также позволяет генерировать строку любой длины.
решение 2 - одна строка кода-хорошо подходит для 22 персонажи
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8);
вы не можете генерировать строки как Решение 1 и строка не имеет того же диапазона из-за фиксированных битов в GUID, но во многих случаях это сделает работу.
решение 3-Немного меньше кода
Guid.NewGuid().ToString("n").Substring(0, 8);
в основном сохраняя это для исторических целей. Он использует немного меньше кода, что, хотя и происходит за счет меньшего диапазона - потому что он использует hex вместо base64 требуется больше символов для представления того же диапазона по сравнению с другими решениями.
что означает больше шансов на столкновение-тестирование его со 100 000 итераций из 8 символьных строк, сгенерированных один дубликат.
вот пример, который я украл из примера Сэма Аллена в Точка Net Perls
Если вам нужно только 8 символов, используйте Path.GetRandomFileName () в системе.Пространство имен IO. Сэм говорит, используя "путь".Метод GetRandomFileName здесь иногда превосходит, потому что он использует RNGCryptoServiceProvider для лучшей случайности. Однако он ограничен 11 случайными символами."
GetRandomFileName всегда возвращает 12-символьную строку с точкой на 9-м характер. Поэтому вам нужно будет удалить период (так как это не случайно), а затем взять 8 символов из строки. На самом деле, вы может просто взять первые 8 символов и не беспокоиться о времени.
public string Get8CharacterRandomString()
{
string path = Path.GetRandomFileName();
path = path.Replace(".", ""); // Remove period.
return path.Substring(0, 8); // Return 8 character string
}
PS: спасибо Сэм
основными целями моего кода:
- распределение строк почти однородно (не заботьтесь о незначительных отклонениях, пока они малы)
- он выводит более нескольких миллиардов строк для каждого набора аргументов. Создание 8-символьной строки (~47 бит энтропии) бессмысленно, если ваш PRNG генерирует только 2 миллиарда (31 бит энтропии) разных значений.
- это безопасно, так как я ожидаю, что люди будут использовать это для паролей или другой безопасности жетоны.
первое свойство достигается путем принятия 64-битного значения по модулю размера алфавита. Для небольших алфавитов (например, 62 символа из вопроса) это приводит к незначительному смещению. Второе и третье свойство достигается с помощью RNGCryptoServiceProvider
вместо System.Random
.
using System;
using System.Security.Cryptography;
public static string GetRandomAlphanumericString(int length)
{
const string alphanumericCharacters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789";
return GetRandomString(length, alphanumericCharacters);
}
public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
if (length < 0)
throw new ArgumentException("length must not be negative", "length");
if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
throw new ArgumentException("length is too big", "length");
if (characterSet == null)
throw new ArgumentNullException("characterSet");
var characterArray = characterSet.Distinct().ToArray();
if (characterArray.Length == 0)
throw new ArgumentException("characterSet must not be empty", "characterSet");
var bytes = new byte[length * 8];
new RNGCryptoServiceProvider().GetBytes(bytes);
var result = new char[length];
for (int i = 0; i < length; i++)
{
ulong value = BitConverter.ToUInt64(bytes, i * 8);
result[i] = characterArray[value % (uint)characterArray.Length];
}
return new string(result);
}
простейший:
public static string GetRandomAlphaNumeric()
{
return Path.GetRandomFileName().Replace(".", "").Substring(0, 8);
}
вы можете получить лучшую производительность, если вы жестко кодируете массив символов и полагаетесь на System.Random
:
public static string GetRandomAlphaNumeric()
{
var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}
если когда-либо вы беспокоитесь, что английские алфавиты могут измениться, и вы можете потерять бизнес, то вы можете избежать жесткого кодирования, но должны работать немного хуже (сопоставимо с Path.GetRandomFileName
подхода)
public static string GetRandomAlphaNumeric()
{
var chars = 'a'.To('z').Concat('0'.To('9')).ToList();
return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}
public static IEnumerable<char> To(this char start, char end)
{
if (end < start)
throw new ArgumentOutOfRangeException("the end char should not be less than start char", innerException: null);
return Enumerable.Range(start, end - start + 1).Select(i => (char)i);
}
последние два подхода выглядят лучше, если их можно сделать методом расширения на System.Random
экземпляра.
просто некоторые сравнения производительности различных ответов в этой теме:
Методы И Установки
// what's available
public static string possibleChars = "abcdefghijklmnopqrstuvwxyz";
// optimized (?) what's available
public static char[] possibleCharsArray = possibleChars.ToCharArray();
// optimized (precalculated) count
public static int possibleCharsAvailable = possibleChars.Length;
// shared randomization thingy
public static Random random = new Random();
// http://stackoverflow.com/a/1344242/1037948
public string LinqIsTheNewBlack(int num) {
return new string(
Enumerable.Repeat(possibleCharsArray, num)
.Select(s => s[random.Next(s.Length)])
.ToArray());
}
// http://stackoverflow.com/a/1344258/1037948
public string ForLoop(int num) {
var result = new char[num];
while(num-- > 0) {
result[num] = possibleCharsArray[random.Next(possibleCharsAvailable)];
}
return new string(result);
}
public string ForLoopNonOptimized(int num) {
var result = new char[num];
while(num-- > 0) {
result[num] = possibleChars[random.Next(possibleChars.Length)];
}
return new string(result);
}
public string Repeat(int num) {
return new string(new char[num].Select(o => possibleCharsArray[random.Next(possibleCharsAvailable)]).ToArray());
}
// http://stackoverflow.com/a/1518495/1037948
public string GenerateRandomString(int num) {
var rBytes = new byte[num];
random.NextBytes(rBytes);
var rName = new char[num];
while(num-- > 0)
rName[num] = possibleCharsArray[rBytes[num] % possibleCharsAvailable];
return new string(rName);
}
//SecureFastRandom - or SolidSwiftRandom
static string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length];
char[] rName = new char[Length];
SolidSwiftRandom.GetNextBytesWithMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(rName);
}
результаты
протестировано в 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 МС)
- дляпеременная элемента (10000x) = 28970 прошедшее клещей (2.897 МС)
- ForLoopNonOptimized (10000x) = 33336 тиков прошло (3,3336 МС)
- повтор (10000x) = 78547 тиков прошло (7,8547 МС)
- GenerateRandomString (10000x) = 27416 тиков прошло (2.7416 МС)
- SecureFastRandom (10000x) = 13176 тиков прошло (5 мс) самый низкий [другая машина]
- SecureFastRandom-NoCache (10000x) = 39541 тиканье прошло (17ms) самый низкий [другая машина]
одна строка кода Membership.GeneratePassword()
делает трюк :)
здесь демо то же самое.
код, написанный Эриком Дж., довольно небрежен (совершенно ясно, что это было 6 лет назад... он, вероятно, не написал бы этот код сегодня), и есть даже некоторые проблемы.
в отличие от некоторых из представленных альтернатив, это криптографически звук.
не соответствует действительности... Существует смещение в пароле (как написано в комментарии), bcdefgh
немного более вероятны, чем другие (a
не потому, что от GetNonZeroBytes
это не генерация байтов со значением нуля, поэтому смещение для a
сбалансирован им), поэтому он не является криптографически звуковым.
Это должно исправить все проблемы.
public static string GetUniqueKey(int size = 6, string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
{
using (var crypto = new RNGCryptoServiceProvider())
{
var data = new byte[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 buffer
byte[] smallBuffer = null;
// Maximum random number that can be used without introducing a
// bias
int maxRandom = byte.MaxValue - ((byte.MaxValue + 1) % chars.Length);
crypto.GetBytes(data);
var result = new char[size];
for (int i = 0; i < size; i++)
{
byte v = data[i];
while (v > maxRandom)
{
if (smallBuffer == null)
{
smallBuffer = new byte[1];
}
crypto.GetBytes(smallBuffer);
v = smallBuffer[0];
}
result[i] = chars[v % chars.Length];
}
return new string(result);
}
}
мы также используем произвольную строку, но мы реализовали ее как помощник строки, поэтому она обеспечивает некоторую гибкость...
public static string Random(this string chars, int length = 8)
{
var randomString = new StringBuilder();
var random = new Random();
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);
другим вариантом может быть использование Linq и агрегатных случайных символов в stringbuilder.
var chars = "abcdefghijklmnopqrstuvwxyz123456789".ToArray();
string pw = Enumerable.Range(0, passwordLength)
.Aggregate(
new StringBuilder(),
(sb, n) => sb.Append((chars[random.Next(chars.Length)])),
sb => sb.ToString());
вопрос: почему я должен тратить свое время с помощью Enumerable.Range
вместо ввода "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"
?
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Main()
{
var randomCharacters = GetRandomCharacters(8, true);
Console.WriteLine(new string(randomCharacters.ToArray()));
}
private static List<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();
}
public static IEnumerable<char> GetRandomCharacters(int count, bool includeLowerCase)
{
var characters = getAvailableRandomCharacters(includeLowerCase);
var random = new Random();
var result = Enumerable.Range(0, count)
.Select(_ => characters[random.Next(characters.Count)]);
return result;
}
}
ответ: Волшебные струны плохие. Кто-нибудь заметил, что не было никакого "I
" в моей строке вверху? Моя мать учила меня не использовать магические струны именно по этой причине...
n.b. 1: Как и многие другие, как @dtb сказал, Не используйте System.Random
если вам нужна криптографической защиты...
n.b. 2: этот ответ не самый эффективный или короткий, но я хотел, чтобы пространство отделяло ответ от вопроса. Цель моего ответа - больше предупредить о волшебных струнах, чем дать причудливый инновационный ответ.
Я искал более конкретный ответ, где я хочу контролировать формат случайной строки и наткнулся на этот пост. Например: номерные знаки (автомобилей) имеют определенный формат (для каждой страны), и я хотел создать случайные номерные знаки.
Я решил написать свой собственный метод расширения для этого. (это для того, чтобы повторно использовать тот же случайный объект, как вы могли бы иметь двойники в многопоточных сценариях).
Я создал суть (https://gist.github.com/SamVanhoutte/808845ca78b9c041e928), но также скопирует класс расширения здесь:
void Main()
{
Random rnd = new Random();
rnd.GetString("1-###-000").Dump();
}
public static class RandomExtensions
{
public static string GetString(this Random 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 = new StringBuilder();
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();
}
private static char getRandomCharacter(Random random)
{
string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return chars[random.Next(chars.Length)];
}
private static char getRandomNumeric(Random random)
{
string nums = "0123456789";
return nums[random.Next(nums.Length)];
}
}
немного более чистая версия решения DTB.
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var list = Enumerable.Repeat(0, 8).Select(x=>chars[random.Next(chars.Length)]);
return string.Join("", list);
настройки стиля могут различаться.
мой простой код одной строки работает для меня:)
string random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o));
Response.Write(random.ToUpper());
Response.Write(random.ToLower());
чтобы развернуть это для любой строки длины
public static string RandomString(int length)
{
//length = length < 0 ? length * -1 : length;
var str = "";
do
{
str += Guid.NewGuid().ToString().Replace("-", "");
}
while (length > str.Length);
return str.Substring(0, length);
}
попробуйте объединить две части: уникальный (последовательность, счетчик или дата) и случайный
public class RandomStringGenerator
{
public static string Gen()
{
return ConvertToBase(DateTime.UtcNow.ToFileTimeUtc()) + GenRandomStrings(5); //keep length fixed at least of one part
}
private static string GenRandomStrings(int strLen)
{
var result = string.Empty;
var Gen = new RNGCryptoServiceProvider();
var data = new byte[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;
}
private static string ConvertToBase(long num, int nbase = 36)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //if you wish make algoritm more secure - change order of letter here
// check if we can convert to another base
if (nbase < 2 || nbase > chars.Length)
return null;
int r;
var newNumber = string.Empty;
// in r we have the offset of the char that was converted to the new base
while (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;
}
}
тесты:
[Test]
public void Generator_Should_BeUnigue1()
{
//Given
var loop = Enumerable.Range(0, 1000);
//When
var str = loop.Select(x=> RandomStringGenerator.Gen());
//Then
var distinct = str.Distinct();
Assert.AreEqual(loop.Count(),distinct.Count()); // Or Assert.IsTrue(distinct.Count() < 0.95 * loop.Count())
}
public static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var random = new Random();
return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
}
после просмотра других ответов и рассмотрения комментариев CodeInChaos, наряду с CodeInChaos по-прежнему предвзятым (хотя и меньше) ответом, я подумал окончательное окончательное решение отрезка и затира. Поэтому, обновляя свой ответ, я решил пойти на все.
для получения обновленной версии этого кода посетите новый репозиторий Hg на Bitbucket:https://bitbucket.org/merarischroeder/secureswiftrandom. Я рекомендую вам скопировать и вставить код из: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default (Убедитесь, что вы нажмете кнопку Raw, чтобы упростить копирование и убедитесь, что у вас есть последняя версия, я думаю, что эта ссылка идет на определенную версию кода, а не последнюю).
обновлены Примечания:
- относительно некоторых других ответов-Если вы знаете длина вывода, вам не нужен StringBuilder, и при использовании ToCharArray это создает и заполняет массив (вам не нужно сначала создавать пустой массив)
- Что касается некоторых других ответов-вы должны использовать NextBytes, а не получать по одному за раз для производительности
- технически вы можете закрепить массив байтов для более быстрого доступа.. обычно это стоит того, когда ваша итерация более 6-8 раз по массиву байтов. (Не здесь)
- использование RNGCryptoServiceProvider для лучшей случайности
- использование кэширование 1 МБ буфера случайных данных - бенчмаркинг показывает, что скорость доступа к кэшированным одиночным байтам ~1000x быстрее-9ms более 1MB против 989ms для некэшированного.
- оптимизированный отказ зоны смещения в моем новом классе.
конец решения вопроса:
static char[] charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(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>
class SecureFastRandom
{
static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
static int lastPosition = 0;
static int remaining = 0;
/// <summary>
/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
/// </summary>
/// <param name="buffer"></param>
public static void DirectGetBytes(byte[] buffer)
{
using (var r = new RNGCryptoServiceProvider())
{
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>
public static void GetBytes(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>
public static byte GetByte()
{
lock (byteCache)
{
return UnsafeGetByte();
}
}
/// <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>
static byte UnsafeGetByte()
{
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>
public static void GetBytesWithMax(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 blocks
DirectGetBytes(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>
static void UnsafeCheckBytesMax(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
}
}
}
для история-мое старое решение для этого ответа, используемый случайный объект:
private static char[] charSet =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[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];
}
}
return new string(rName);
}
производительность:
- SecureFastRandom - первый одиночный запуск = ~9-33ms. Неуловимый. продолжается: 5 мс (иногда он доходит до 13 мс) более 10 000 итераций с одной средней итерацией= 1.5 микросекунд.. Примечание: обычно требуется 2, но иногда до 8 обновлений кэша-зависит от сколько одиночных байтов превышает зону смещения
- случайные - первый одиночный запуск = ~0-1ms. Неуловимый. продолжается: 5 мс за 10 000 итераций. С одной средней итерацией= .5 микросекунд.. Примерно с той же скоростью.
теперь в однострочном вкусе.
private string RandomName
{
get
{
return new string(
Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
.Select(s =>
{
var cryptoResult = new byte[4];
new RNGCryptoServiceProvider().GetBytes(cryptoResult);
return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
})
.ToArray());
}
}
решение без использования Random
:
var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);
var randomStr = new string(chars.SelectMany(str => str)
.OrderBy(c => Guid.NewGuid())
.Take(8).ToArray());
вот вариант решения Eric J, т. е. криптографически звук, для WinRT (Windows Store App):
public static string GenerateRandomString(int length)
{
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var result = new StringBuilder(length);
for (int i = 0; i < length; ++i)
{
result.Append(CryptographicBuffer.GenerateRandomNumber() % chars.Length);
}
return result.ToString();
}
Если производительность имеет значение (особенно, когда длина высока):
public static string GenerateRandomString(int length)
{
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var result = new System.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();
}
Я знаю, что это не лучший способ. Но ты можешь попробовать это.
string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters
str = str.Replace(".","");
Console.WriteLine("Random string: " + str);
Я не знаю, как криптографически звучит это, но это более читабельно и лаконично, чем более сложные решения (imo), и это должно быть более "случайным", чем System.Random
решений.
return alphabet
.OrderBy(c => Guid.NewGuid())
.Take(strLength)
.Aggregate(
new StringBuilder(),
(builder, c) => builder.Append(c))
.ToString();
Я не могу решить, считаю ли я эту версию или следующую "красивее", но они дают те же самые результаты:
return new string(alphabet
.OrderBy(o => Guid.NewGuid())
.Take(strLength)
.ToArray());
конечно, он не оптимизирован для скорости, поэтому, если критически важно генерировать миллионы случайных строк каждую секунду, попробуйте другой один!
Примечание: это решение не допускает повторений символов в алфавите, и алфавит должен быть одинакового или большего размера, чем выходная строка, что делает этот подход менее желательным в некоторых обстоятельствах, все зависит от вашего варианта использования.
Если ваши значения не являются полностью случайными, но на самом деле могут зависеть от чего - то-вы можете вычислить md5 или sha1 хэш этого "somwthing", а затем усечь его до любой длины, которую вы хотите.
также вы можете генерировать и усекать guid.
public static class StringHelper
{
private static readonly Random random = new Random();
private const int randomSymbolsDefaultCount = 8;
private const string availableChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static int randomSymbolsIndex = 0;
public static string GetRandomSymbols()
{
return GetRandomSymbols(randomSymbolsDefaultCount);
}
public static string GetRandomSymbols(int count)
{
var index = randomSymbolsIndex;
var result = new string(
Enumerable.Repeat(availableChars, count)
.Select(s => {
index += random.Next(s.Length);
if (index >= s.Length)
index -= s.Length;
return s[index];
})
.ToArray());
randomSymbolsIndex = index;
return result;
}
}
вот механизм для генерации случайной Альфа-цифровой строки (я использую это для генерации паролей и тестовых данных) без определения алфавита и чисел,
CleanupBase64 удалит необходимые части в строке и будет рекурсивно добавлять случайные буквенно-цифровые буквы.
public static string GenerateRandomString(int length)
{
var numArray = new byte[length];
new RNGCryptoServiceProvider().GetBytes(numArray);
return CleanUpBase64String(Convert.ToBase64String(numArray), length);
}
private static string CleanUpBase64String(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);
}
очень простое решение. Он использует ASCII значения и просто генерирует "случайные" символы между ними.
public static class UsernameTools
{
public static string GenerateRandomUsername(int length = 10)
{
Random random = new Random();
StringBuilder sbuilder = new StringBuilder();
for (int x = 0; x < length; ++x)
{
sbuilder.Append((char)random.Next(33, 126));
}
return sbuilder.ToString();
}
}
вы просто используете сборки SRVTextToImage
. И напишите ниже код для генерации случайной строки.
CaptchaRandomImage c1 = new CaptchaRandomImage();
string text = c1.GetRandomString(8);
в основном он используется для реализации капчи. Но в вашем случае это тоже работает. Надеюсь, это поможет.