我如何在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[不同的机器]

其他回答

不是100%确定,因为我没有测试这里的每个选项,但在我测试的选项中,这个是最快的。用秒表计时,它显示9-10滴答,所以如果速度比安全更重要,试试这个:

 private static Random random = new Random(); 
 public static string Random(int length)
     {   
          var stringChars = new char[length];

          for (int i = 0; i < length; i++)
              {
                  stringChars[i] = (char)random.Next(0x30, 0x7a);                  
                  return new string(stringChars);
              }
     }

解决方案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,所以与其他解决方案相比,它需要更多的字符来表示相同的范围。

这意味着碰撞的可能性更大——用10万次迭代测试8个字符串,生成一个副本。

一种简单且高度安全的方法可能是生成加密Aes密钥。

public static string GenerateRandomString()
{
    using Aes crypto = Aes.Create();
    crypto.GenerateKey();
    return Convert.ToBase64String(crypto.Key);
}

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

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

尝试将两部分结合起来:独特(序列、计数器或日期)和随机

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;

        using (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)
    {
        const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //if you wish to make the algorithm 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())
    }