我如何在c#中生成一个随机的8个字符的字母数字字符串?


当前回答

在这个线程中只是一些不同答案的性能比较:

方法与设置

// 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的字符串,生成:

from Linq = chdgmevhcy [10] from Loop = gtnoaryhxr [10] from Select = rsndbztyby [10] from GenerateRandomString = owyefjjakj [10] from securefastrrandom = VzougLYHYP [10] from securefastrrandom - nocache = oVQXNGmO1S [10]

性能数据会有细微的变化,偶尔NonOptimized会更快,有时ForLoop和GenerateRandomString会切换谁领先。

LinqIsTheNewBlack (10000x) = 96762 ticks elapsed (9.6762 ms) ForLoop (10000x) = 28970滴答流逝(2.897毫秒) ForLoopNonOptimized (10000x) = 33336滴答流逝(3.3336毫秒) 重复(10000x) = 78547滴答流逝(7.8547毫秒) GenerateRandomString (10000x) = 27416 tick elapsed (2.7416 ms) securefastrrandom (10000x) = 13176滴答流逝(5ms)最低[不同的机器] securefastrrandom - nocache (10000x) = 39541 ticks elapsed (17ms) low[不同的机器]

其他回答

您只需使用程序集SRVTextToImage。并编写下面的代码生成随机字符串。

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

它主要用于实现验证码。但对你来说也一样。希望能有所帮助。

我知道这不是最好的办法。但是你可以试试这个。

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

如果你的值不是完全随机的,但实际上可能依赖于某些东西——你可以计算出“某个东西”的md5或sha1哈希,然后将其截断为你想要的任何长度。

你也可以生成和截断一个guid。

我听说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类。)

更新。net 6。RNGCryptoServiceProvider被标记为obsolete。相反,调用RandomNumberGenerator.Create()。答案中的代码已相应更新。

根据评论更新。原始实现生成a-h的时间为1.95%,其余字符的时间为1.56%。更新生成所有字符~1.61%的时间。 FRAMEWORK支持- . 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 (var crypto = RandomNumberGenerator.Create())
            {
                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")}%");
            }
        }
    }
}

更新7/25/2022

根据评论中的一个问题,我很好奇这种分布是否真的是随机的。

我不是统计学家,但我可以在电视上扮演一个。如果一位真正的统计学家愿意插话,那将是最受欢迎的。

有62个可能的输出值(A-Za-Z0-9)和int。用于选择数组索引的最大值。int。MaxValue % 62是1,所以一个字符被选中的概率是其他字符的十亿分之一。我们可以通过在索引之前随机旋转输出值数组来进一步减少选择偏差。

t检验或其他统计度量将是确定输出结果中是否存在偏差的最佳方法,但这不是我在午休时间可以完成的工作,因此我留给您对上述代码的修改,以度量与预期的偏差。注意,它趋于零。

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

const int REPETITIONS = 1_000_000;
const int KEY_SIZE = 32;
int TASK_COUNT = Environment.ProcessorCount - 1;

var expectedPercentage = 100.0 / KeyGenerator.chars.Length;

var done = false;
var iterationNr = 1;
var totalRandomSymbols = 0L;

var grandTotalCounts = new Dictionary<char, long>();
foreach (var ch in KeyGenerator.chars) grandTotalCounts.Add(ch, 0);

while (!done)
{
    var experiments = Enumerable.Range(0, TASK_COUNT).Select(i => Task.Run(Experiment)).ToArray();
    Task.WaitAll(experiments);
    var totalCountsThisRun = experiments.SelectMany(e => e.Result)
        .GroupBy(e => e.Key)
        .Select(e => new { e.Key, Count = e.Select(_ => _.Value).Sum() })
        .ToDictionary(e => e.Key, e => e.Count);

    foreach (var ch in KeyGenerator.chars)
        grandTotalCounts[ch] += totalCountsThisRun[ch];

    var totalChars = grandTotalCounts.Values.Sum();
    totalRandomSymbols += totalChars;

    var distributionScores = KeyGenerator.chars.Select(ch =>
    new
    {
        Symbol = ch,
        OverUnder = (100.0 * grandTotalCounts[ch] / totalChars) - expectedPercentage

    });

    Console.WriteLine($"Iteration {iterationNr++}. Total random symbols: {totalRandomSymbols:N0}");
    foreach (var chWithValue in distributionScores.OrderByDescending(c => c.OverUnder))
    {
        Console.WriteLine($"{chWithValue.Symbol}: {chWithValue.OverUnder:#.00000}%");
    }

    done = Console.KeyAvailable;        
}

Dictionary<char, long> Experiment()
{
    var counts = new Dictionary<char, long>();
    foreach (var ch in KeyGenerator.chars) counts.Add(ch, 0);

    for (int i = 0; i < REPETITIONS; i++)
    {
        var key = KeyGenerator.GetUniqueKey(KEY_SIZE);
        foreach (var ch in key) counts[ch]++;
    }

    return counts;
}

public class KeyGenerator
{
    internal static readonly char[] chars =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();

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