it-swarm.com.ru

Как я могу генерировать случайные буквенно-цифровые строки?

Как я могу генерировать случайную 8-символьную буквенно-цифровую строку в C #?

821
KingNestor

Я слышал, что 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());
}

(Примечание: использование класса Random делает это неподходящим для всего, что связано с безопасностью, например, для создания паролей или токенов. Используйте класс RNGCryptoServiceProvider, если вам нужен сильный случайный генератор чисел.)

1489
dtb
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.

(Примечание: использование класса Random делает это неподходящим для всего, что связано с безопасностью, например, для создания паролей или токенов. Используйте класс RNGCryptoServiceProvider, если вам нужен сильный случайный генератор чисел.)

328
Dan Rigby

Эта реализация (найденная через гугл) мне кажется правильной.

В отличие от некоторых представленных альтернатив, этот криптографически обоснован .

using System.Security.Cryptography;
using System.Text;

namespace UniqueKey
{
    public class KeyGenerator
    {
        public static string GetUniqueKey(int size)
        {
            char[] chars =
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
            byte[] data = new byte[size];
            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
            {
                crypto.GetBytes(data);
            }
            StringBuilder result = new StringBuilder(size);
            foreach (byte b in data)
            {
                result.Append(chars[b % (chars.Length)]);
            }
            return result.ToString();
        }
    }
}

Выбрал тот из обсуждения альтернатив здесь

295
Eric J.

Решение 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 символов в шестнадцатеричном формате всегда " 4 "- по крайней мере, в версии 6 GUID.

Это решение также позволяет генерировать строку любой длины.

Решение 2 - Одна строка кода - подходит до 22 символов

Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8);

Вы не можете генерировать строки, пока Решение 1 , и строка не имеет такой же диапазон из-за фиксированных битов в GUID, но во многих случаев это сделает работу.

Решение 3 - немного меньше кода

Guid.NewGuid().ToString("n").Substring(0, 8);

В основном это здесь для исторических целей. В нем используется немного меньше кода, хотя это связано с меньшим диапазоном - поскольку он использует шестнадцатеричный код вместо base64, ему требуется больше символов для представления того же диапазона по сравнению с другими решениями.

Что означает больше шансов на столкновение - тестирование с 100 000 итераций по 8 символьных строк сгенерировало один дубликат.

184
Douglas

Вот пример, который я украл из примера Сэма Аллена в Dot Net Perls

Если вам нужно всего 8 символов, используйте Path.GetRandomFileName () в пространстве имен System.IO. Сэм говорит, что использование метода Path.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: спасибо Сэм

59
Adam Porad

Основные цели моего кода:

  1. Распределение строк практически равномерно (не обращайте внимания на незначительные отклонения, если они небольшие)
  2. Он выводит более нескольких миллиардов строк для каждого набора аргументов. Генерирование 8-символьной строки (~ 47 бит энтропии) не имеет смысла, если ваш PRNG генерирует только 2 миллиарда (31 бит энтропии) различных значений.
  3. Это безопасно, так как я ожидаю, что люди будут использовать это для паролей или других токенов безопасности.

Первое свойство достигается путем принятия 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];
    var result = new char[length];
    using (var cryptoProvider = new RNGCryptoServiceProvider())
    {
        cryptoProvider.GetBytes(bytes);
    }
    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);
}
37
CodesInChaos

Простейший:

public static string GetRandomAlphaNumeric()
{
    return Path.GetRandomFileName().Replace(".", "").Substring(0, 8);
}

Вы можете добиться лучшей производительности, если жестко закодировать массив char и положиться на 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.

29
nawfal

Просто некоторые сравнения производительности различных ответов в этой теме:

Методы и настройка

// 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 мс)
  • ForLoop (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 пройденных тиков (17 мс) наименьшее [Другой компьютер]
20
drzaus

Одна строка кода Membership.GeneratePassword() делает свое дело :)

Вот демо для того же.

17
Pooran

Код, написанный Эриком Дж., Довольно небрежный (совершенно очевидно, что он написан 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);
    }
}
11
xanatos

Вопрос: Почему я должен тратить свое время, используя 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"? Моя мама научила меня не использовать магические струны именно по этой причине ...

нотабене 1: Как и многие другие, такие как @dtb, не используйте System.Random, если вам нужна криптографическая защита ...

нотабене 2: Этот ответ не самый эффективный или самый короткий, но я хотел, чтобы место отделяло ответ от вопроса. Цель моего ответа - больше предостеречь от волшебных строк, чем дать причудливый инновационный ответ.

6
Wai Ha Lee

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

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);
6
Mr. Pumpkin

Другим вариантом может быть использование Linq и агрегирование случайных символов в строителе строк.

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());
6
AAD

Мой простой однострочный код работает на меня :)

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);
    }
6
Raj kumar

Немного более чистая версия решения 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);

Ваши предпочтения стиля могут отличаться.

5
Rob Deary

Изучив другие ответы и рассмотрев комментарии CodeInChaos, наряду с CodeInChaos, все еще предвзятым (хотя и менее) ответом, я подумал окончательное окончательное решение для вырезки и вставки необходимо. Поэтому, обновляя свой ответ, я решил сделать все возможное.

Чтобы получить актуальную версию этого кода, посетите новый репозиторий Hg в Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Я рекомендую вам скопировать и вставить код из: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRanderfilefilefilefile.dll (убедитесь, что вы нажали кнопку Raw, чтобы было проще копировать и убедитесь, что у вас установлена ​​последняя версия, я думаю, что эта ссылка ведет на конкретную версию кода, а не на последнюю).

Обновленные заметки:

  1. Относительно некоторых других ответов - если вы знаете длину вывода, вам не нужен StringBuilder, и при использовании ToCharArray это создает и заполняет массив (вам не нужно сначала создавать пустой массив)
  2. Относительно некоторых других ответов - Вы должны использовать NextBytes, а не получать по одному для производительности
  3. Технически вы можете закрепить байтовый массив для более быстрого доступа. Обычно это стоит того, чтобы выполнить итерацию более 6-8 раз по байтовому массиву. (Не сделано здесь)
  4. Использование RNGCryptoServiceProvider для лучшей случайности
  5. Использование кэширования 1 МБ буфера случайных данных - сравнительный анализ показывает, что скорость кэшированного однобайтового доступа составляет ~ 1000 раз быстрее - 9 мкс за 1 МБ против 989 мс для не кэшированного.
  6. Оптимизировано отклонение зоны смещения в моем новом классе.

Конец решения вопроса:

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);
    }

Спектакль:

  1. SecureFastRandom - Первый одиночный запуск = ~ 9-33мс . Незаметный. Постоянно : 5 мс (иногда до 13 мс) за 10000 итераций, с одной средней итерацией = 1,5 микросекунды. . Примечание: обычно требуется 2, но иногда до 8 обновлений кэша - зависит от того, сколько отдельных байтов превышает зону смещения
  2. Случайный - Первый одиночный прогон = ~ 0-1мс . Незаметный. Постоянно : 5 мс более 10000 итераций. С одной средней итерацией = . 5 микросекунд. . Примерно с той же скоростью.

Также проверьте:

Эти ссылки являются еще одним подходом. Буферизацию можно было бы добавить к этой новой кодовой базе, но наиболее важным было изучение различных подходов к устранению смещения и сравнительный анализ скоростей и плюсов/минусов.

4
Merari Schroeder

Я искал более конкретный ответ, где хочу контролировать формат случайной строки и наткнулся на этот пост. Например: номерные знаки (автомобилей) имеют определенный формат (для каждой страны), и я хотел создать случайные номерные знаки.
Я решил написать свой собственный метод расширения Random для этого. (это делается для того, чтобы повторно использовать один и тот же объект Random, так как в сценариях с многопоточностью вы можете получить двойные значения). Я создал Gist ( 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)];
    }
}
4
Sam Vanhoutte

Ужасно, я знаю, но я просто не мог с собой поделать:


namespace ConsoleApplication2
{
    using System;
    using System.Text.RegularExpressions;

    class Program
    {
        static void Main(string[] args)
        {
            Random adomRng = new Random();
            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);
        }
    }
}
4
james
 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());
    }
4
Tejas

Попробуйте объединить две части: уникальную (последовательность, счетчик или дата) и случайную

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())
    }
3
RouR

Теперь в однострочном аромате.

private string RandomName
    {
        get
        {
            return new string(
                Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                    .Select(s =>
                    {
                        var cryptoResult = new byte[4];
                        using (var cryptoProvider = new RNGCryptoServiceProvider())
                            cryptoProvider.GetBytes(cryptoResult);
                        return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                    })
                    .ToArray());
        }
    }
2
Matas Vaitkevicius

Вот вариант решения Eric J, то есть криптографически обоснованный, для WinRT (приложение для Магазина Windows):

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();
}
2
huyc

Решение без использования Random:

var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);

var randomStr = new string(chars.SelectMany(str => str)
                                .OrderBy(c => Guid.NewGuid())
                                .Take(8).ToArray());
2
w.b

Я не знаю, насколько криптографически это звучит, но он более читабелен и лаконичен, чем более сложные решения (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());

Конечно, он не оптимизирован по скорости, поэтому, если критически важно генерировать миллионы случайных строк каждую секунду, попробуйте другую!

ПРИМЕЧАНИЕ. Это решение не допускает повторения символов в алфавите, и алфавит ДОЛЖЕН иметь такой же или больший размер, чем выходная строка, что делает этот подход менее желательным в некоторых обстоятельствах, все зависит от вашего варианта использования.

1
sara

Я знаю, что это не лучший способ. Но вы можете попробовать это.

string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters
str = str.Replace(".","");
Console.WriteLine("Random string: " + str);
1
Sagar

Если ваши значения не являются полностью случайными, но на самом деле могут зависеть от чего-то - вы можете вычислить хэш md5 или sha1 для этого 'somwthing', а затем обрезать его до желаемой длины.

Также вы можете генерировать и усекать guid.

0
Alexey B.

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

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);
        }
0
Dhanuka777
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;
    }
}
0
KregHEk