如何生成随机字母数字字符串?

Kin*_*tor 891 .net c# random

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

dtb*_*dtb 1576

我听说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());
}
Run Code Online (Sandbox Code Playgroud)

(注意:使用Random该类会使其不适用于任何与安全相关的内容,例如创建密码或令牌.RNGCryptoServiceProvider如果需要强大的随机数生成器,请使用该类.)

  • @xaisoft:小写字母留给读者练习. (37认同)
  • @Alex:我已经运行了一些快速测试,当生成更长的字符串时,它似乎可以非常线性地扩展(只要实际上有足够的可用内存).话虽如此,Dan Rigby的答案几乎是每次测试中的两倍. (22认同)
  • 以下行比给定的返回新字符串(Enumerable.Range(1,length).Select(_ => chars [random.Next(chars.Length)])更多内存(因此时间)效率.ToArray( ));` (12认同)
  • 好.如果你的标准是它使用linq并且它有一个糟糕的代码叙述那么它肯定是蜜蜂的膝盖.代码叙述和实际执行路径都是相当低效和间接的.不要误会我的意思,我是一个巨大的代码行家(我喜欢python),但这几乎是一个rube goldberg机器. (5认同)
  • 虽然这在技术上回答了这个问题,但它的输出是非常误导的.生成8个随机字符听起来可能有*非常多的结果,而这最多会产生20亿个不同的结果.而在实践中甚至更少.您还应该添加一个BIG FAT警告,不要将其用于任何安全相关的东西. (5认同)

Dan*_*gby 345

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);
Run Code Online (Sandbox Code Playgroud)

不像Linq解决方案那么优雅.( - :

(注意:使用Random该类会使其不适用于任何与安全相关的内容,例如创建密码或令牌.RNGCryptoServiceProvider如果需要强大的随机数生成器,请使用该类.)

  • @Alex:这不是绝对最快的答案,但它是最快的"真实"答案(即那些允许控制所用字符和字符串长度的答案). (4认同)
  • @xaisoft 在循环之外创建 Random() 对象的实例。如果您在短时间内创建大量 Random() 实例,则调用 .Next() 将返回与 Random() 使用基于时间的种子相同的值。 (3认同)
  • @Alex:Adam Porad的`GetRandomFileName`解决方案速度更快,但不允许对所使用的字符进行任何控制,最大长度为11个字符。道格拉斯(Douglas)的`Guid'解决方案具有闪电般的速度,但是字符限制为A-F0-9,最大长度为32个字符。 (2认同)
  • @xaisoft不要将此答案用于任何关键的安全性,如密码.`System.Random`不适合安全. (2认同)

Eri*_* J. 309

这个实现(通过谷歌找到)看起来很健康.

与提供的一些替代方案不同,这个方案是加密声音.

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的替代品讨论中挑选出一个

  • 字母略有偏差(255%62!= 0).尽管存在这个小缺陷,但它是迄今为止最好的解决方案. (24认同)
  • 减少偏差的一种可能性是,请求`4*maxSize`随机字节,然后使用`(UInt32)(BitConverter.ToInt32(data,4*i)%chars.Length`.我也使用`GetBytes`而不是`GetNonZeroBytes`.最后你可以删除第一次调用`GetNonZeroBytes`.你没有使用它的结果. (14认同)
  • 请注意,如果您想要加密,无偏的随机性,这不是*声音.(如果你不想那样那么为什么首先使用'RNGCSP`?)使用mod来索引`chars`数组意味着你将得到偏置输出,除非`chars.Length`碰巧是一个除数256 (13认同)
  • 有趣的事实:AZ az 0-9是62个字符.人们指出字母偏差,因为256%62!= 0. YouTube的视频ID是AZ az 0-9,以及" - "和"_",它产生64个可能的字符,均匀分为256个字符.巧合?我想不是!:) (12认同)
  • 这看起来对我来说是正确的方法 - 随机密码,盐,熵等不应使用Random()生成,Random()针对速度进行优化并生成可重现的数字序列; 另一方面,RNGCryptoServiceProvider.GetNonZeroBytes()产生不可再现的野生数字序列. (11认同)
  • 这里没有必要使用GetNonZeroBytes(),实际上这很糟糕,因为这会使分布偏离小写的"a".应该使用普通的GetBytes(). (6认同)
  • 我在此脚本中提出了建议的所有建议:https://gist.github.com/diegojancic/9f78750f05550fa6039d2f6092e461e5 (6认同)
  • Amir是对的,`byte [] data = new byte [1]; ... crypto.GetNonZeroBytes(数据);`这两行绝对没有效果.您正在生成一个包含1个随机字节的数组,然后您永远不会看它.`new byte [length]`用不同的实例替换数组,在该点之前你对`data`所做的一切都被丢弃了. (4认同)
  • @ pseudonym27:是的.变量名称`maxSize`应该可以称为`size`.密码将是该变量中指定的大小,而不是"最大"该大小. (4认同)
  • 正如其他人所说,这个答案确实是一个很好的答案,除了它有偏见(实际上并没有那么轻微)有两个原因:第一个 256 % 62 != 0,第二个你应该使用 GetBytes。 (4认同)
  • @bkqc:问题不在于某个点是否设置了单个位,而是一组可能值的问题.如果黑客意识到值249-255未被使用,则简化了强力黑客攻击策略.就像我告诉你的那样"我想的是从1到10的数字,你试着猜它.哦,它不是8或9." 最后一部分让你的游戏更轻松. (2认同)

Dou*_*las 196

解决方案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);
    }
}
Run Code Online (Sandbox Code Playgroud)

此解决方案比使用GUID具有更多的范围,因为GUID具有几个始终相同且因此不是随机的固定位,例如十六进制中的13个字符始终为"4" - 至少在版本6 GUID中.

此解决方案还允许您生成任意长度的字符串.

解决方案2 - 一行代码 - 最多22个字符

Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8);
Run Code Online (Sandbox Code Playgroud)

只要解决方案1和字符串由于GUID中的固定位而没有相同的范围,就无法生成字符串,但在很多情况下,这将完成工作.

解决方案3 - 略少的代码

Guid.NewGuid().ToString("n").Substring(0, 8);
Run Code Online (Sandbox Code Playgroud)

大部分时间都是为了历史目的.它使用稍微少一点的代码,虽然这是为了减少范围 - 因为它使用十六进制代替base64,与其他解决方案相比,它需要更多的字符来表示相同的范围.

这意味着更多的碰撞机会 - 用100,000个迭代的8个字符串测试它产生一个重复.

  • @Alex:他将GUID缩短为8个字符,因此碰撞的概率远高于GUID. (71认同)
  • 1)GUID被设计为唯一的,而不是随机的.虽然当前版本的Windows生成的V4 GUID确实是随机的,但这并不能保证.例如,旧版本的Windows使用V1 GUID,您可能会失败.2)只使用十六进制字符会显着降低随机字符串的质量.从47到32位.3)人们低估了碰撞概率,因为他们为个人配对.如果生成100k 32位值,则它们之间可能会发生一次冲突.看生日问题. (32认同)
  • Guid.NewGuid().ToString("n")将保持破折号,不需要Replace()调用.但应该提到的是,GUID只有0-9和AF.组合的数量"足够好",但是没有接近*true*字母数字随机字符串允许的数量.碰撞的几率是1:4,294,967,296 - 与随机的32位整数相同. (30认同)
  • 除了书呆子之外,没有人可以欣赏这个:)是的,你是绝对正确的,8字符限制有所作为. (22认同)
  • 你实际上生成了副本?令人惊讶的是,在5,316,911,983,139,663,491,615,228,241,121,400,000个可能的GUID组合. (21认同)
  • 停止浪费GUID!我们只有5,316,911,983,139,663,491,615,228,241,121,400,000! (7认同)
  • (发生这种情况的几率是 1.8807909613156600127499784595556e-27,或者几乎为 0) (2认同)

Ada*_*rad 65

这是我从Dot Net Perls的 Sam Allen案例中偷走的一个例子

如果只需要8个字符,则在System.IO命名空间中使用Path.GetRandomFileName().Sam说使用"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
}
Run Code Online (Sandbox Code Playgroud)

PS:谢谢Sam

  • 这很好用.我通过100,000次迭代运行它,并且从未有过重复的名称.但是,我**确实找到了几个粗俗的词(英文).甚至没有想到这个,除了列表中的第一个中有一个F***.如果您将此用于用户将看到的内容,那么只需要抬头. (25认同)
  • @techturtle感谢您的警告.我认为任何使用字母表中所有字母的随机字符串生成都存在粗俗词语的风险. (3认同)
  • 有时会有一些低俗的词汇,但是如果您让它运行足够长时间,最终它会写成莎士比亚。(仅是宇宙的一生。:) (2认同)

Cod*_*aos 37

我的代码的主要目标是:

  1. 字符串的分布几乎是一致的(只要它们很小,就不关心微小的偏差)
  2. 它为每个参数集输出超过几十亿个字符串.如果您的PRNG仅生成20亿(31位熵)不同的值,则生成8个字符的字符串(~47位熵)是没有意义的.
  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);
}
Run Code Online (Sandbox Code Playgroud)


naw*_*fal 29

最简单的:

public static string GetRandomAlphaNumeric()
{
    return Path.GetRandomFileName().Replace(".", "").Substring(0, 8);
}
Run Code Online (Sandbox Code Playgroud)

如果您对char数组进行硬编码并依赖于System.Random以下内容,则可以获得更好的性能:

public static string GetRandomAlphaNumeric()
{
    var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}
Run Code Online (Sandbox Code Playgroud)

如果您担心英语字母可能会在某个时间发生变化并且您可能会失去业务,那么您可以避免硬编码,但应该执行稍差(与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);
}
Run Code Online (Sandbox Code Playgroud)

如果你可以在System.Random实例上使它们成为扩展方法,那么最后两种方法看起来会更好.

  • 这在[theDailyWTF.com](https://thedailywtf.com/articles/ten-times-as-unique)上作为CodeSOD文章提供. (4认同)

drz*_*aus 21

只是对这个帖子中各种答案的一些性能比较:

方法和设置

// 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);
}
Run Code Online (Sandbox Code Playgroud)

结果

在LinqPad中测试过.对于字符串大小10,生成:

  • 来自Linq = chdgmevhcy [10]
  • 来自Loop = gtnoaryhxr [10]
  • 来自Select = rsndbztyby [10]
  • 来自GenerateRandomString = owyefjjakj [10]
  • 来自SecureFastRandom = VzougLYHYP [10]
  • 来自SecureFastRandom-NoCache = oVQXNGmO1S [10]

而业绩数字往往略有不同,非常偶然NonOptimized其实是快,有时ForLoopGenerateRandomString切换谁是处于领先地位.

  • 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个刻度(5ms)最低[不同的机器]
  • SecureFastRandom-NoCache(10000x)= 39541个刻度(17ms)最低[不同的机器]

  • 知道哪些创造了欺骗会很有趣. (3认同)

Poo*_*ran 18

一行代码Membership.GeneratePassword()就是诀窍:)

这是一个相同的演示.


xan*_*tos 12

Eric J.编写的代码非常草率(很明显它是从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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Ami*_*adi 8

具有加密安全性的最简单、最灵活的解决方案(.NET Core 3.0+):

如果您使用 .NET Core 3.0 或更高版本,则可以GetInt32在类上使用新的静态方法(加密安全)RandomNumberGenerator为给定字符集生成随机索引,并以这种方式轻松填充结果。

这种方法比本答案中提出的方法要简单得多;而且它还提供了完全的灵活性,因为您可以传入任何您想要的字符集。

public static string GenerateRandomString(int length, IEnumerable<char> charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
{
    var charArray = charSet.Distinct().ToArray();
    char[] result = new char[length];
    for (int i = 0; i < length; i++)
        result[i] = charArray[RandomNumberGenerator.GetInt32(charArray.Length)];
    return new string(result);
}
Run Code Online (Sandbox Code Playgroud)

用法:

public static string GenerateRandomString(int length, IEnumerable<char> charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
{
    var charArray = charSet.Distinct().ToArray();
    char[] result = new char[length];
    for (int i = 0; i < length; i++)
        result[i] = charArray[RandomNumberGenerator.GetInt32(charArray.Length)];
    return new string(result);
}
Run Code Online (Sandbox Code Playgroud)


Mr.*_*kin 7

我们也使用自定义字符串随机,但我们实现的是字符串的帮助器,因此它提供了一些灵活性......

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();
}
Run Code Online (Sandbox Code Playgroud)

用法

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();
Run Code Online (Sandbox Code Playgroud)

要么

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16);
Run Code Online (Sandbox Code Playgroud)


AAD*_*AAD 6

另一个选择可能是使用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());
Run Code Online (Sandbox Code Playgroud)


Wai*_*Lee 6

问题:为什么我要浪费时间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;
    }
}
Run Code Online (Sandbox Code Playgroud)

答:魔术弦很不好.是否有人注意到I我的字符串顶部没有" "?我母亲教我不要因为这个原因而使用魔法弦......

nb 1:正如许多其他像@dtb所说的那样,System.Random如果你需要加密安全性,请不要使用...

nb 2:这个答案不是最有效或最短的,但我希望空间能够将答案与问题分开.我的回答的目的更多是警告魔法字符串,而不是提供一个奇特的创新答案.


Raj*_*mar 6

我简单的一行代码对我有用:)

string  random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o));

Response.Write(random.ToUpper());
Response.Write(random.ToLower());
Run Code Online (Sandbox Code Playgroud)

为此扩展任何长度的字符串

    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);
    }
Run Code Online (Sandbox Code Playgroud)

  • 对于 5 位数字字符,这需要 0 毫秒,但接受的答案需要 2 毫秒。当您有 Guid 类时,为什么要重新发明轮子:) 对答案的改进应该是 .ToString("N") 删除连字符 (3认同)

Tej*_*jas 6

 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());
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

在查看了其他答案并考虑了CodeInChaos的评论之后,再加上CodeInChaos仍然有偏见(尽管更少),我认为需要最终的最终剪切和粘贴解决方案。因此,在更新答案时,我决定全力以赴。

有关此代码的最新版本,请访问Bitbucket上的新Hg存储库:https : //bitbucket.org/merarischroeder/secureswiftrandom。我建议您从以下位置复制并粘贴代码:https : //bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&default.fileviewer=file-view -make原始按钮可简化复制过程,并确保您具有最新版本,我认为此链接将转到代码的特定版本,而不是最新版本。

更新说明:

  1. 关于其他答案-如果您知道输出的长度,则不需要StringBuilder,并且在使用ToCharArray时,这将创建并填充数组(不需要先创建空数组)
  2. 关于其他答案-您应该使用NextBytes,而不是一次获得一个以提高性能
  3. 从技术上讲,您可以固定字节数组以实现更快的访问..在字节数组上进行6-8次以上的迭代时,通常值得这样做。(此处未完成)
  4. 使用RNGCryptoServiceProvider获得最佳随机性
  5. 使用1MB的随机数据缓冲区进行缓存-基准测试表明,缓存的单字节访问速度快约1000倍-1MB占用9ms,而未缓存则为989ms。
  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);
}
Run Code Online (Sandbox Code Playgroud)

但是您需要我的新(未经测试)课程:

/// <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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于历史记录-我对此答案的较旧解决方案使用了Random对象:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

性能:

  1. SecureFastRandom - 第一次运行 = 〜9-33ms。难以察觉。持续进行:10,000次迭代中5 毫秒(有时上升到13 毫秒),平均一次迭代= 1.5微秒。。注意:通常需要2次,但有时最多需要刷新8次-取决于超出偏置区域的单个字节数
  2. 随机 - 第一次单次运行 = 〜0-1ms。难以察觉。持续:10,000次迭代中5ms。单个平均迭代= 0.5微秒。。大约相同的速度。

还要签出:

这些链接是另一种方法。可以将缓冲添加到此新代码库中,但是最重要的是探索各种方法来消除偏差,并确定速度和优点/缺点。

  • 1)为什么所有这些魔术常数?您指定了输出长度* 3 *次。只需将其定义为常量或参数即可。您可以使用charSet.Length而不是62。2)没有锁定的静态“随机”表示此代码不是线程安全的。3)降低0-255 mod 62会引入可检测的偏差。4)您不能在char数组上使用`ToString`,它总是返回`“ System.Char []”`。您需要改用`new String(rName)`。 (5认同)

Rou*_*ouR 5

尝试结合两部分:唯一(序列、计数器或日期)和随机

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

    [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())
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

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);
Run Code Online (Sandbox Code Playgroud)

您的风格偏好可能会有所不


Mis*_*sky 5

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

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