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

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

27.08.2009 23:07:24
Какие ограничения у вас есть на набор символов? Просто символы английского языка и 0-9? Смешанный случай?
Eric J. 27.08.2009 23:15:09
Jonas Elfström 27.08.2009 23:15:47
Обратите внимание, что вы НЕ должны использовать какой-либо метод, основанный на Randomклассе, для генерации паролей. Посев семян Randomимеет очень низкую энтропию, поэтому он не очень безопасен. Используйте криптографический PRNG для паролей.
CodesInChaos 9.03.2011 18:47:54
Было бы неплохо включить языковую локализацию в этот вопрос. Особенно, если ваш графический интерфейс должен обслуживать китайский или болгарский язык!
Peter Jamsmenson 25.09.2015 23:48:14
Что-то с таким большим количеством голосов и таким количеством качественных ответов не заслуживает того, чтобы быть отмеченным как закрытое. Я голосую за то, чтобы он был вновь открыт.
John Coleman 16.10.2017 12:52:53
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());
}

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

1663
1.03.2019 15:18:12
@Alex: Я провел несколько быстрых тестов, и кажется, что при генерации более длинных строк он масштабируется в значительной степени линейно (при условии, что на самом деле доступно достаточно памяти). Сказав это, ответ Дэн Ригби был почти в два раза быстрее, чем этот в каждом тесте.
LukeH 28.08.2009 00:33:15
Хорошо. Если ваш критерий в том, что он использует linq и что у него паршивое повествование, то это определенно колени пчелы. Как повествование кода, так и фактический путь выполнения довольно неэффективны и косвенны. Не поймите меня неправильно, я большой хипстер (я люблю Python), но это в значительной степени машина Руба Гольдберга.
eremzeit 29.09.2011 15:41:19
Хотя это технически отвечает на вопрос, его вывод очень вводит в заблуждение. Генерация 8 случайных символов звучит так, как будто результатов может быть очень много, тогда как в лучшем случае это дает 2 миллиарда различных результатов. А на практике еще меньше. Вы также должны добавить БОЛЬШОЕ ЖИРНОЕ предупреждение, чтобы не использовать его для каких-либо вещей, связанных с безопасностью.
CodesInChaos 17.03.2012 20:50:00
@xaisoft: строчные буквы оставляются в качестве упражнения для читателя.
dtb 30.09.2013 14:29:25
Следующая строка более эффективна по памяти (и, следовательно, по времени), чем заданнаяreturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams 11.11.2016 18:06:17

ОБНОВЛЕНО на основе комментариев. Исходная реализация генерировала ах ~ 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
{
    public class KeyGenerator
    {
        internal static readonly char[] chars =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); 

        public static string GetUniqueKey(int size)
        {            
            byte[] data = new byte[4*size];
            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
            {
                crypto.GetBytes(data);
            }
            StringBuilder result = new StringBuilder(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();
        }

        public static string GetUniqueKeyOriginal_BIASED(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();
        }
    }
}

На основе обсуждения альтернатив здесь и обновляется / модифицируется на основе комментариев ниже.

Вот небольшой тестовый набор, который демонстрирует распределение символов в старых и обновленных выходных данных. Для глубокого обсуждения анализа случайности , проверьте random.org.

using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;

namespace CryptoRNGDemo
{
    class Program
    {

        const int REPETITIONS = 1000000;
        const int KEY_SIZE = 32;

        static void Main(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();
        }

        static void PerformTest(int repetitions, int keySize, Func<int, string> generator)
        {
            Dictionary<char, int> counts = new Dictionary<char, int>();
            foreach (var ch in UniqueKey.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 in UniqueKey.KeyGenerator.chars)
            {
                Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");
            }
        }
    }
}
332
25.07.2019 06:41:33
Это похоже на правильный подход ко мне - случайные пароли, соли, энтропия и т. Д. Не должны генерироваться с использованием Random (), который оптимизирован по скорости и генерирует воспроизводимые последовательности чисел; RNGCryptoServiceProvider.GetNonZeroBytes (), с другой стороны, создает дикие последовательности чисел, которые НЕ являются воспроизводимыми.
mindplay.dk 18.04.2011 20:09:08
Буквы слегка смещены (255% 62! = 0). Несмотря на этот незначительный недостаток, это, безусловно, лучшее решение здесь.
CodesInChaos 17.03.2012 20:52:28
Обратите внимание, что это не так, если вам нужна криптостойкость, непредвзятая случайность. (И если вы не хотите этого, то зачем использовать RNGCSPв первую очередь?) Использование mod для индексации charsмассива означает, что вы получите смещенный вывод, если не chars.Lengthпроизойдет делитель 256.
LukeH 3.04.2012 16:35:05
Одна возможность значительно уменьшить смещение - это запрос 4*maxSizeслучайных байтов, а затем использование (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. Я бы тоже использовал GetBytesвместо GetNonZeroBytes. И, наконец, вы можете удалить первый вызов GetNonZeroBytes. Вы не используете его результат.
CodesInChaos 4.04.2012 08:19:19
Интересный факт: AZ az 0-9 - это 62 символа. Люди указывают на смещение букв, потому что 256% 62! = 0. Идентификаторы видео YouTube - это AZ az 0-9, а также «-» и «_», которые выдают 64 возможных символа, которые делятся на 256 равномерно. Стечение обстоятельств? Думаю, нет! :)
qJake 26.09.2016 18:25:47
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класс, если вам нужен сильный генератор случайных чисел.)

368
11.04.2019 18:27:31
@ Алекс: Это не самый быстрый ответ, но это самый быстрый «реальный» ответ (т. Е. Из тех, которые позволяют контролировать используемые символы и длину строки).
LukeH 28.08.2009 00:56:06
@Alex: GetRandomFileNameрешение Адама Порада быстрее, но не позволяет контролировать используемые символы, и максимально возможная длина составляет 11 символов. GuidРешение Дугласа молниеносно, но символы ограничены A-F0-9, а максимальная возможная длина составляет 32 символа.
LukeH 28.08.2009 01:01:08
@ Адам: Да, вы можете объединить результаты нескольких вызовов, GetRandomFileNameно тогда (а) вы потеряете свое преимущество в производительности и (б) ваш код станет более сложным.
LukeH 28.08.2009 09:08:07
@xaisoft создайте свой экземпляр объекта Random () вне вашего цикла. Если вы создадите много экземпляров Random () за короткий промежуток времени, то вызов .Next () вернет то же значение, что и Random (), использующий основанное на времени начальное число.
Dan Rigby 30.09.2013 18:16:56
@xaisoft Не используйте этот ответ для чего-либо критически важного для безопасности, например для паролей. System.Randomне подходит для безопасности.
CodesInChaos 21.10.2013 10:14:29

Вот пример, который я украл у Сэма Аллена в 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: спасибо Сэм

72
27.08.2009 23:37:43
Это хорошо работает. Я провел 100 000 итераций и у меня никогда не было повторяющегося имени. Тем не менее, я сделал найти несколько вульгарных слов (на английском языке). Даже не подумал бы об этом, кроме одного из первых в списке, в котором было F ***. Просто один на один, если вы используете это для чего-то, что увидит пользователь.
techturtle 9.10.2012 22:35:46
@techturtle Спасибо за предупреждение. Я предполагаю, что есть риск для вульгарных слов с любой случайной генерацией строки, которая использует все буквы в алфавите.
Adam Porad 10.10.2012 23:38:46
красиво и просто, но не подходит для длинных струн ... проголосуйте за этот хороший трюк
Maher Abuthraa 28.02.2014 09:55:53
Этот метод, кажется, возвращает только строчные буквенно-цифровые строки.
jaybro 5.06.2014 14:30:00
Время от времени бывают вульгарные слова, но если вы продолжите в том же духе, то в конце концов это напишет Шекспир. (Всего несколько жизней Вселенной. :)
Slothario 30.04.2018 17:12:12

Решение 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» - по крайней мере, в GUID версии 6.

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

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

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

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

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

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

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

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

201
20.03.2018 17:31:51
Вы фактически сгенерировали дубликат? Удивительно 5,316,911,983,139,663,491,615,228,241,121,400,000 возможных комбинаций GUID.
Alex 28.08.2009 00:10:35
@ Алекс: Он сокращает GUID до 8 символов, поэтому вероятность коллизий намного выше, чем у GUID.
dtb 28.08.2009 00:19:50
Никто не может оценить это, кроме ботаников :) Да, вы абсолютно правы, ограничение в 8 символов имеет значение.
Alex 28.08.2009 00:36:17
Guid.NewGuid (). ToString ("n") сохранит тире, вызов Replace () не требуется. Но следует отметить, что GUID только 0-9 и AF. Количество комбинаций «достаточно хорошее», но не близко к тому, что допускает настоящая буквенно-цифровая случайная строка. Вероятность столкновения составляет 1: 4 294 967 296 - то же самое, что и случайное 32-разрядное целое число.
richardtallent 28.08.2009 00:40:51
1) GUID разработаны так, чтобы быть уникальными, а не случайными. Хотя текущие версии Windows генерируют идентификаторы GUID V4, которые действительно являются случайными, это не гарантируется. Например, в более старых версиях Windows использовались идентификаторы GUID V1, в которых может произойти сбой. 2) Просто использование шестнадцатеричных символов значительно снижает качество случайной строки. От 47 до 32 бит. 3) Люди недооценивают вероятность столкновения, так как они дают ее для отдельных пар. Если вы генерируете 100k 32-битных значений, у вас, вероятно, есть одно столкновение между ними. Смотрите проблему дня рождения.
CodesInChaos 16.11.2012 12:33:18

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


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
28.08.2009 00:37:59

Изучив другие ответы и рассмотрев комментарии 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, чтобы упростить копирование и убедиться, что у вас установлена ​​последняя версия, я думаю, что эта ссылка ведет на конкретную версию кода, а не на последнюю).

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

  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 мс) в течение 10 000 итераций, с одной средней итерацией = 1,5 микросекунды. , Примечание: обычно требуется 2, но иногда до 8 обновлений кэша - зависит от того, сколько отдельных байтов превышает зону смещения
  2. Случайный - Первый одиночный прогон = ~ 0-1мс . Незаметный. Постоянно : 5 мс, более 10000 итераций. С одной средней итерацией = .5 микросекунд. , Примерно с той же скоростью.

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

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

5
30.11.2018 03:25:56
Я обнаружил некоторые незначительные улучшения производительности вашего метода, которые, похоже, были
drzaus 13.06.2013 16:46:44
1) Почему все эти магические константы? Вы указали длину вывода три раза. Просто определите его как константу или параметр. Вы можете использовать charSet.Lengthвместо 62. 2) Статический Randomбез блокировки означает, что этот код не является потокобезопасным. 3) уменьшение 0-255 мод 62 вводит обнаруживаемое смещение. 4) Вы не можете использовать ToStringмассив символов, который всегда возвращается "System.Char[]". Вы должны использовать new String(rName)вместо этого.
CodesInChaos 4.06.2014 10:04:20
Спасибо @CodesInChaos, я никогда не думал об этих вещах тогда. Все еще только с использованием класса Random, но это должно быть лучше. Я не мог придумать лучшего способа обнаружить и исправить входные данные смещения.
Todd 20.02.2016 09:44:23
Немного глупо начинать со слабой RNG ( System.Random), а затем осторожно избегать любых ошибок в вашем собственном коде. На ум приходит выражение «полировка какашки».
CodesInChaos 20.02.2016 11:03:35
@CodesInChaos И теперь ученик превзошел своего хозяина
Todd 20.02.2016 12:02:14

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

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

0
29.03.2010 15:48:04

Другим вариантом может быть использование 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
8.12.2012 20:39:31

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

  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);
}
38
7.11.2018 06:46:05
Нет пересечения с 64 x Z и Math.Pow (2, Y). Таким образом, увеличение числа уменьшает предвзятость, но не устраняет ее. Я обновил свой ответ ниже, мой подход состоял в том, чтобы отбросить случайные входные данные и заменить их на другое значение.
Todd 20.02.2016 10:00:43
@ Тодд Я знаю, что это не устраняет смещение, но я выбрал простоту этого решения вместо устранения практически несущественного смещения.
CodesInChaos 20.02.2016 10:32:55
Я согласен, что в большинстве случаев это практически не имеет значения. Но теперь я обновил мой, чтобы быть таким же быстрым, как Random, и немного более безопасным, чем ваш. Все с открытым исходным кодом для всех, чтобы поделиться. Да, я потратил слишком много времени на это ...
Todd 20.02.2016 12:06:14
Если мы используем провайдера RNG, есть ли у нас способ избежать теоретической предвзятости? Я не уверен ... Если Тодд имеет в виду способ, когда он генерирует дополнительное случайное число (когда мы находимся в зоне смещения), то это может быть ошибочным предположением. ГСЧ имеет практически линейное распределение всех генерируемых значений в среднем. Но это не значит, что у нас не будет локальной корреляции между сгенерированными байтами. Таким образом, дополнительный байт только для зоны смещения может дать нам некоторый уклон, но по другой причине. Скорее всего, это смещение будет очень маленьким. НО в этом случае увеличение общего количества сгенерированных байтов является более простым способом.
Maxim 31.07.2017 16:18:11
@Maxim Вы можете использовать отклонение, чтобы полностью устранить смещение (при условии, что базовый генератор совершенно случайный). Взамен код может выполняться произвольно долго (с экспоненциально малой вероятностью).
CodesInChaos 31.07.2017 17:56:14

Простейший:

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экземпляре.

32
4.06.2014 10:35:33
Использование chars.Selectочень уродливо, так как оно зависит от размера выходного файла, не превышающего размер алфавита.
CodesInChaos 4.06.2014 10:09:12
@CodesInChaos Я не уверен, что понимаю вас. Вы имеете в виду в 'a'.To('z')подходе?
nawfal 4.06.2014 10:18:34
1) chars.Select().Take (n) `работает только если chars.Count >= n. Выбор последовательности, которую вы на самом деле не используете, немного не интуитивен, особенно с этим неявным ограничением длины. Я бы лучше использовал Enumerable.Rangeили Enumerable.Repeat. 2) Сообщение об ошибке «конечный символ должен быть меньше начального символа» является неправильным путем / отсутствует a not.
CodesInChaos 4.06.2014 10:20:41
@CodesInChaos, но в моем случае chars.Countэто путь > n. Также я не понимаю неинтуитивную часть. Что делает все использует Takeне интуитивным не так ли? Я не верю этому. Спасибо за указание на опечатку.
nawfal 4.06.2014 10:34:53
Это представлено на DailyWTF.com как статья CodeSOD.
user177800 3.10.2018 05:33:05

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

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

// 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 мс) наименьшее [Другой компьютер]
22
21.02.2016 11:50:42
Было бы интересно узнать, какие из них создали дуплики.
Rebecca 1.08.2013 12:43:03
@Junto - чтобы выяснить, что приводит к дубликатам, что-то вроде того var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());, где вы заменяете EachRandomizingMethod... каждый метод
drzaus 11.09.2013 17:06:21
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
7.04.2014 08:08:35
1) статические методы должны быть потокобезопасными. 2) Какой смысл увеличивать индекс, а не использовать результат random.Nextнапрямую? Усложняет код и не дает ничего полезного.
CodesInChaos 4.06.2014 10:01:03

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

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);
7
26.06.2014 15:12:32

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

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

19
3.05.2018 08:58:41
Похоже, Microsoft переместила ссылку. Другой пример кода находится по адресу msdn.microsoft.com/en-us/library/ms152017 или aspnet.4guysfromrolla.com/demos/GeneratePassword.aspx или developer.xamarin.com/api/member/…
Pooran 2.08.2015 18:26:24
Я думал об этом, но не смог избавиться от буквенно-цифровых символов, поскольку 2-й аргумент - это МИНИМАЛЬНЫЕ не буквенные символы
ozzy432836 5.04.2018 10:29:03

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

string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters
str = str.Replace(".","");
Console.WriteLine("Random string: " + str);
1
15.07.2014 12:42:49
Как эта линия? Console.WriteLine ($ "Случайная строка: {Path.GetRandomFileName (). Replace (". "," ")}"); это одна строка.
PmanAce 23.05.2018 15:02:35

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

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
15.06.2015 07:51:51
1) Вы можете использовать символьные литералы вместо значений ASCII, связанных с этими символами. 2) В коде совпадения интервалов возникла ошибка «один за другим». Вам нужно использовать <=и >=вместо <и >. 3) Я бы добавил ненужные скобки вокруг &&выражений, чтобы было ясно, что они имеют приоритет, но, конечно, это только стилистический выбор.
CodesInChaos 24.10.2016 16:58:24
+1 Хорошо для устранения смещения и добавления тестирования. Я не уверен, почему вы добавляете вашу случайную строку к строке, полученной из отметки времени? Кроме того, вам все еще нужно избавиться от вашего RNGCryptoServiceProvider
monty 7.06.2018 22:11:49

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

Теперь в однолинейном аромате.

private string RandomName()
{
        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());
}
3
17.04.2020 07:44:43
Использование свойства для чего-то, что изменяется при каждом доступе, довольно сомнительно. Я бы рекомендовал вместо этого использовать метод.
CodesInChaos 11.01.2016 16:34:59
RNGCryptoServiceProviderследует утилизировать после использования.
Tsahi Asher 10.01.2017 16:25:21
Я исправил проблему IDisposable, но это все еще очень сомнительно, создавая новый RNGCryptoServiceProvider для каждого письма.
piojo 7.11.2018 06:58:24
@CodesInChaos сделано, теперь метод.
Matas Vaitkevicius 17.04.2020 07:52:00

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

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

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

6
22.02.2015 18:17:34
Почему меня волнует, что нет " I?"
Christine 12.12.2016 19:01:52
Буквенно-цифровой (без учета регистра) есть [A-Z0-9]. Если, случайно, ваша случайная строка только когда-либо покрывает [A-HJ-Z0-9]результат, не покрывает весь допустимый диапазон, что может быть проблематично.
Wai Ha Lee 13.12.2016 16:14:49
Как это было бы проблематично? Так что не содержит I. Это потому, что на одного персонажа меньше, и его легче взломать? Какова статистика взламываемых паролей, которые содержат 35 символов в диапазоне, а не 36. Я думаю, что я скорее рискну ... или просто проверю тростниковый диапазон символов ... чем включу весь этот дополнительный мусор в мой код. Но это я. Я имею в виду, чтобы не быть прикладом, я просто говорю. Иногда я думаю, что программисты склонны идти по сверхсложному пути ради того, чтобы быть сверхсложными.
Christine 13.12.2016 16:22:14
Это зависит от варианта использования. Очень часто исключают такие символы, как Iи Oиз этих типов случайных строк, чтобы люди не путали их с 1и 0. Если вас не волнует наличие удобочитаемой строки, хорошо, но если это то, что кому-то может понадобиться напечатать, то на самом деле разумно удалить эти символы.
Chris Pratt 22.08.2017 03:04:15

Немного более чистая версия решения 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
27.04.2015 20:47:05
Это намного лучше и эффективнее, чем принятый ответ.
Wedge 27.05.2016 16:49:38

Очень простое решение Он использует значения 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();
    }

}
-1
21.06.2015 22:46:18

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

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

var randomStr = new string(chars.SelectMany(str => str)
                                .OrderBy(c => Guid.NewGuid())
                                .Take(8).ToArray());
2
11.08.2015 10:02:05
NewGuid использует случайное внутреннее. Так что это все еще использует случайное, это просто скрывает это.
Wedge 27.05.2016 16:50:25

Код, написанный Эриком Дж., Довольно неряшливый (совершенно очевидно, что он написан 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);
    }
}
13
12.08.2015 07:53:36

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

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
5.04.2018 11:12:58
Мне тоже нравится метод
ozzy432836 5.04.2018 10:19:28

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

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
30.09.2015 02:55:02
Вы объявили GenerateRandomStringи позвонили GetRandomStringизнутри SanitiseBase64String. Кроме того, вы заявили , SanitiseBase64String и вызов CleanUpBase64Stringв GenerateRandomString.
Wai Ha Lee 30.09.2015 02:53:05

Вот вариант решения 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
27.10.2015 14:20:20
Это не криптографически обоснованно. Существует небольшое смещение из-за того, что операция модуля не распределяет всю ширину Улонга в равной степени на 62 символа.
Lie Ryan 30.05.2017 15:24:03
 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());
    }
5
24.11.2015 08:46:17

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

Вы просто используете сборку SRVTextToImage. И напишите ниже код для генерации случайной строки.

CaptchaRandomImage c1 = new CaptchaRandomImage();
            string text = c1.GetRandomString(8);

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

-3
16.02.2016 19:05:59
То есть вы говорите, что нам следует использовать какую-то стороннюю библиотеку, изначально разработанную для генерации CAPTCHA для генерации случайной строки?
Tsahi Asher 10.01.2017 16:30:46
Строка не единственное, что случайно в этом предложении! я люблю это, определенно самый оригинальный!
BanksySan 12.01.2017 18:27:35