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

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

1061647 次浏览

我听说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被标记为过时。相反,请调用随机数生成器。创建()。答案中的代码已相应更新。

根据注释更新。原始实现生成a-h的时间约为1.95%,其余字符的时间约为1.56%。更新生成所有字符的时间约为1.61%。

框架支持-. NET Core 3(以及支持. NET Standard 2.1或更高版本的未来平台)提供了一种加密可靠的方法随机数生成器。进入t 32()来生成所需范围内的随机整数。

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

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

基于对备选方案这里的讨论,并基于以下评论进行更新/修改。

这是一个小测试工具,演示了字符在旧输出和更新输出中的分布。

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

更新日期2022/7/25

基于评论中的一个问题,我很好奇分布是否真的是随机的。

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

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

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();}}
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类。)

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

如果你只需要8个字符,那么在System.IO的命名空间中使用Path. GetR随机文件名()。Sam说使用“这里的Path. GetR随机文件名方法有时会更好,因为它使用RNGCryptoServiceProvider来获得更好的随机性。但是,它被限制为11个随机字符。”

总是返回一个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:谢谢Sam

解决方案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 upvar 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);

主要是为了历史目的将其保留在此处。它使用的代码略少,尽管这是减少范围的代价-因为它使用十六进制而不是base 64,与其他解决方案相比,它需要更多字符来表示相同的范围。

这意味着更多的碰撞机会-用10万次8个字符串的迭代生成一个副本来测试它。

可怕的,我知道,但我无法控制自己:

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

在审查了其他答案并考虑了CodeInChaos的评论,以及CodeInChaos仍然有偏见(尽管较少)的答案之后,我认为需要一个最终最终剪切和粘贴溶液。所以在更新我的答案时,我决定全力以赴。

要获取此代码的最新版本,请访问新的Hg存储库:https://bitbucket.org/merarischroeder/secureswiftrandom。我建议您从:https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&; fileviewer=file-view-default复制并粘贴代码(确保单击原始按钮以使复制更容易,并确保您拥有最新版本,我认为此链接指向特定版本的代码,而不是最新版本)。

更新备注:

  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 conveniencestatic 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 possiblechar[] 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 blocksDirectGetBytes(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}}}

对于历史-我对这个答案的旧解决方案,使用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 conveniencestatic 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 possiblechar[] 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. 安全快速随机访问-第一单跑=~9-33ms。难以察觉。进行中5ms(有时长达13ms)超过10,000次迭代,单次平均迭代=1.5微秒。。注意:通常需要2次,但偶尔最多8次缓存刷新-取决于超过偏置区的单个字节数
  2. 随机-第一单跑=~0-1ms。难以察觉。进行中5ms超过10,000次迭代。单个平均迭代=.5微秒。。大约相同的速度。

还检查:

这些链接是另一种方法。缓冲可以添加到这个新的代码库中,但最重要的是探索不同的方法来消除偏见,并对速度和优缺点进行基准测试。

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

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

另一种选择是使用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());

我的代码的主要目标是:

  1. 字符串的分布几乎是均匀的(不关心微小的偏差,只要它们很小)
  2. 它为每个参数集输出超过几十亿个字符串。如果您的PRNG仅生成20亿(31位熵)不同的值,则生成8个字符串(约47位熵)毫无意义。
  3. 它是安全的,因为我希望人们将其用于密码或其他安全令牌。

第一个属性是通过取64位值模字母大小来实现的。对于小字母(例如问题中的62个字符),这会导致可以忽略不计的偏差。第二个和第三个属性是通过使用#0而不是#1来实现的。

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

最简单的:

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实例上的扩展方法,那么最后两种方法看起来会更好。

只是这个线程中各种答案的一些性能比较:

方法和设置

// what's availablepublic static string possibleChars = "abcdefghijklmnopqrstuvwxyz";// optimized (?) what's availablepublic static char[] possibleCharsArray = possibleChars.ToCharArray();// optimized (precalculated) countpublic static int possibleCharsAvailable = possibleChars.Length;// shared randomization thingypublic static Random random = new Random();

// http://stackoverflow.com/a/1344242/1037948public string LinqIsTheNewBlack(int num) {return new string(Enumerable.Repeat(possibleCharsArray, num).Select(s => s[random.Next(s.Length)]).ToArray());}
// http://stackoverflow.com/a/1344258/1037948public 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/1037948public 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 SolidSwiftRandomstatic 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=chdgrevhcy[10]
  • 来自Loop=gtnoaryhxr[10]
  • 从选择=rsndbztyby[10]
  • 生成字符串[10]
  • 来自SecureFastRandom=VzougLYHYP[10]
  • 从SecureFastRandom NoCache=oVQXNGmO1S[10]

性能数字往往略有不同,偶尔NonOptimized实际上更快,有时ForLoopGenerateRandomString会切换谁领先。

  • LinqIsTheNewBlack(10000x)=96762滴答声(9.6762 ms)
  • ForLoop(10000x)=28970滴答声(2.897 ms)
  • ForLoopNonOptimized(10000x)=33336滴答声(3.3336 ms)
  • 重复(10000x)=78547滴答声(7.8547 ms)
  • 生成随机字符串(10000x)=27416个滴答声(2.7416毫秒)
  • SecureFastRandom(10000x)=13176滴答(5ms)最低[不同机器]
  • SecureFastRandom-NoCache(10000x)=39541滴答(17ms)最低[不同机器]
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;}}

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

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

一行代码#0就可以解决问题:)

这是一个相同的demo

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

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

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

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-9code > 65 && code < 90 || // A-Zcode > 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 baseif (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 basewhile (num >= nbase){r = (int)(num % nbase);newNumber = chars[r] + newNumber;num = num / nbase;}// the last number to convertnewNumber = chars[(int)num] + newNumber;
return newNumber;}}

测试:

    [Test]public void Generator_Should_BeUnigue1(){//Givenvar loop = Enumerable.Range(0, 1000);//Whenvar str = loop.Select(x=> RandomStringGenerator.Gen());//Thenvar distinct = str.Distinct();Assert.AreEqual(loop.Count(),distinct.Count()); // Or Assert.IsTrue(distinct.Count() < 0.95 * loop.Count())}

我在寻找一个更具体的答案,我想控制随机字符串的格式,遇到了这篇文章。例如:车牌(汽车)有特定的格式(每个国家),我想创建随机车牌。
我决定为此编写自己的Random扩展方法(这是为了重用相同的Random对象,因为在多线程场景中可以使用双精度)。我创建了一个gist(https://gist.github.com/SamVanhoutte/808845ca78b9c041e928),但也会在这里复制扩展类:

void Main(){Random rnd = new Random();rnd.GetString("1-###-000").Dump();}
public static class RandomExtensions{public static string GetString(this Random random, string format){// Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c// Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)StringBuilder result = new StringBuilder();for(int formatIndex = 0; formatIndex < format.Length ; formatIndex++){switch(format.ToUpper()[formatIndex]){case '0': result.Append(getRandomNumeric(random)); break;case '#': result.Append(getRandomCharacter(random)); break;default : result.Append(format[formatIndex]); break;}}return result.ToString();}
private static char getRandomCharacter(Random random){string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";return chars[random.Next(chars.Length)];}
private static char getRandomNumeric(Random random){string nums = "0123456789";return nums[random.Next(nums.Length)];}}

现在是单线的味道。

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

提问:为什么我要浪费时间使用Enumerable.Range而不是输入"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"

using System;using System.Collections.Generic;using System.Linq;
public class Test{public static void Main(){var randomCharacters = GetRandomCharacters(8, true);Console.WriteLine(new string(randomCharacters.ToArray()));}
private static List<char> getAvailableRandomCharacters(bool includeLowerCase){var integers = Enumerable.Empty<int>();integers = integers.Concat(Enumerable.Range('A', 26));integers = integers.Concat(Enumerable.Range('0', 10));
if ( includeLowerCase )integers = integers.Concat(Enumerable.Range('a', 26));
return integers.Select(i => (char)i).ToList();}
public static IEnumerable<char> GetRandomCharacters(int count, bool includeLowerCase){var characters = getAvailableRandomCharacters(includeLowerCase);var random = new Random();var result = Enumerable.Range(0, count).Select(_ => characters[random.Next(characters.Count)]);
return result;}}

答复:魔术弦不好。有没有人注意到我的弦顶部没有“I”?我妈妈教我不要用魔术弦就是因为这个原因…

注1:正如@dtb所说,如果您需要加密安全,请不要使用System.Random

注意2:这个答案不是最有效的,也不是最短的,但我希望有空间把答案和问题分开。我回答的目的更多的是警告人们不要受到魔法的影响,而不是提供一个花哨的创新答案。

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

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

非常简单的解决方案。它使用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();}
}

不使用Random的解决方案:

var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);
var randomStr = new string(chars.SelectMany(str => str).OrderBy(c => Guid.NewGuid()).Take(8).ToArray());

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 bufferbyte[] smallBuffer = null;
// Maximum random number that can be used without introducing a// biasint 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);}}

我的简单的一行代码为我工作:)

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

这是一种生成随机字母数字字符串的机制(我用它来生成密码和测试数据),而无需定义字母和数字,

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 lettersinput.ToUpper().Substring(0, maxLength);}

以下是Eric J的解决方案的变体,即用于WinRT(Windows Store App)的加密声音:

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

我不知道这在密码学上听起来如何,但它比迄今为止更复杂的解决方案(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());

当然,它没有针对速度进行优化,所以如果每秒生成数百万个随机字符串是关键任务,请尝试另一个!

注意:此解决方案不允许在字母表中重复符号,并且字母表必须等于或大于输出字符串的大小,使得这种方法在某些情况下不太理想,这完全取决于您的用例。

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

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

它主要用于实现验证码。但在您的情况下,它也有效。希望它有帮助。

有一个令人敬畏的nuget包使这变得如此简单。

var myObject = new Faker<MyObject>().RuleFor(p => p.MyAlphaNumericProperty, f => f.Random.AlphaNumeric(/*lenght*/ 7)).Generate();

一个很好的例子是这里

不是100%确定,因为我没有在这里测试每个选项,但在我测试的选项中,这个是最快的。

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

对于加密和非加密,有效地:

public static string GenerateRandomString(int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") =>new Random().GenerateRandomString(length, charset);
public static string GenerateRandomString(this Random random, int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") =>RandomString(random.NextBytes, length, charset.ToCharArray());
public static string GenerateRandomCryptoString(int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"){using (var crypto = new System.Security.Cryptography.RNGCryptoServiceProvider())return crypto.GenerateRandomCryptoString(length, charset);}
public static string GenerateRandomCryptoString(this RNGCryptoServiceProvider random, int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") =>RandomString(random.GetBytes, length, charset.ToCharArray());
private static string RandomString(Action<byte[]> fillRandomBuffer, int length, char[] charset){if (length < 0)throw new ArgumentOutOfRangeException(nameof(length), $"{nameof(length)} must be greater or equal to 0");if (charset is null)throw new ArgumentNullException(nameof(charset));if (charset.Length == 0)throw new ArgumentException($"{nameof(charset)} must contain at least 1 character", nameof(charset));
var maxIdx = charset.Length;var chars = new char[length];var randomBuffer = new byte[length * 4];fillRandomBuffer(randomBuffer);
for (var i = 0; i < length; i++)chars[i] = charset[BitConverter.ToUInt32(randomBuffer, i * 4) % maxIdx];
return new string(chars);}

使用生成器和LINQ。不是最快的选择(特别是因为它不会一次性生成所有字节),但非常整洁且可扩展:

private static readonly Random _random = new Random();
public static string GenerateRandomString(int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") =>new string(_random.GetGenerator().RandomChars(charset.ToCharArray()).Take(length).ToArray());
public static string GenerateRandomCryptoString(int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"){using (var crypto = new System.Security.Cryptography.RNGCryptoServiceProvider())return new string(crypto.GetGenerator().RandomChars(charset.ToCharArray()).Take(length).ToArray());}
public static IEnumerable<char> RandomChars(this Func<uint, IEnumerable<uint>> randomGenerator, char[] charset){if (charset is null)throw new ArgumentNullException(nameof(charset));if (charset.Length == 0)throw new ArgumentException($"{nameof(charset)} must contain at least 1 character", nameof(charset));
return randomGenerator((uint)charset.Length).Select(r => charset[r]);}
public static Func<uint, IEnumerable<uint>> GetGenerator(this Random random){if (random is null)throw new ArgumentNullException(nameof(random));
return GeneratorFunc_Inner;
IEnumerable<uint> GeneratorFunc_Inner(uint maxValue){if (maxValue > int.MaxValue)throw new ArgumentOutOfRangeException(nameof(maxValue));
return Generator_Inner();
IEnumerable<uint> Generator_Inner(){var randomBytes = new byte[4];while (true){random.NextBytes(randomBytes);yield return BitConverter.ToUInt32(randomBytes, 0) % maxValue;}}}}
public static Func<uint, IEnumerable<uint>> GetGenerator(this System.Security.Cryptography.RNGCryptoServiceProvider random){if (random is null)throw new ArgumentNullException(nameof(random));
return Generator_Inner;
IEnumerable<uint> Generator_Inner(uint maxValue){var randomBytes = new byte[4];while (true){random.GetBytes(randomBytes);yield return BitConverter.ToUInt32(randomBytes, 0) % maxValue;}}}

一个更简单的版本,仅对非加密字符串使用LINQ:

private static readonly Random _random = new Random();
public static string RandomString(int length, string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") =>new string(_random.GenerateChars(charset).Take(length).ToArray());
public static IEnumerable<char> GenerateChars(this Random random, string charset){if (charset is null) throw new ArgumentNullException(nameof(charset));if (charset.Length == 0) throw new ArgumentException($"{nameof(charset)} must contain at least 1 character", nameof(charset));
return random.Generator(charset.Length).Select(r => charset[r]);}
public static IEnumerable<int> Generator(this Random random, int maxValue){if (random is null) throw new ArgumentNullException(nameof(random));
return Generator_Inner();
IEnumerable<int> Generator_Inner() { while (true) yield return random.Next(maxValue); }}

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

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

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

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

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

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

用法:

string randomAlphanumericString = GenerateRandomString(length: 10);

包含所有字母字符和数字的解决方案,您可以随意更改:

public static string RandomString(int length){Random rand = new Random();string charbase = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";return new string(Enumerable.Range(0,length).Select(_ => charbase[rand.Next(charbase.Length)]).ToArray());}

如果你喜欢单行方法;)

public static Random rand = new Random();public const string charbase = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 

public static string RandomString(int length) =>new string(Enumerable.Range(0,length).Select(_ => charbase[rand.Next(charbase.Length)]).ToArray());