如何在C#中生成随机的字母数字string?
如何在C#中生成随机的8个字符的字母数字string?
我听说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类的使用使得这不适用于任何与安全相关的事情,例如创build密码或令牌。
如果您需要强大的随机数生成器,请使用RNGCryptoServiceProvider类。)
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解决scheme那么优雅。 ( – :
(注意:Random类的使用使得这个不适用于任何与安全相关的事情 ,例如创build密码或令牌。如果你需要一个强大的随机数生成器,使用RNGCryptoServiceProvider类。
这个实现(通过谷歌发现)听起来很合适。
与其他一些替代scheme不同的是,这一个是密码良好的 。
using System.Security.Cryptography; using System.Text; namespace UniqueKey { public class KeyGenerator { public static string GetUniqueKey(int maxSize) { char[] chars = new char[62]; chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); byte[] data = new byte[1]; using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) { crypto.GetNonZeroBytes(data); data = new byte[maxSize]; crypto.GetNonZeroBytes(data); } StringBuilder result = new StringBuilder(maxSize); foreach (byte b in data) { result.Append(chars[b % (chars.Length)]); } return result.ToString(); } } }
从这里的替代scheme的讨论中挑选出一个
为什么不使用Guid?
Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 8);
刚刚经过100,000次迭代testing,只产生一个重复。
编辑:技术上你不需要打电话。 破折号在Guid的前8个字符之后。 我习惯于为我工作的项目生成16个字符的随机数字。 应该:
Guid.NewGuid().ToString().Substring(0, 8);
编辑2:如果你需要生成8个以上的字符,你可以在下面做一下richardtaltallent的提示,用“n”作为.ToString方法的格式值,
Guid.NewGuid().ToString("n").Substring(0, numOfCharsNeeded);
编辑3:要获得全方位的字母数字字符,您可以使用:
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8);
这是我从Dot Net Perls的 Sam Allen例子中偷走的一个例子
如果您只需要8个字符,则使用System.IO命名空间中的Path.GetRandomFileName()。 Sam说,在这里使用“Path.GetRandomFileName”方法有时会更好,因为它使用RNGCryptoServiceProvider来获得更好的随机性,但是它仅限于11个随机字符。
GetRandomFileName始终返回一个12个字符的string,并在第9个字符处显示一个句点。 所以你需要去掉句点(因为这不是随机的),然后从string中取8个字符。 实际上,你可以拿前8个字,而不用担心这个时期。
public string Get8CharacterRandomString() { string path = Path.GetRandomFileName(); path = path.Replace(".", ""); // Remove period. return path.Substring(0, 8); // Return 8 character string }
PS:谢谢萨姆
我的代码的主要目标是:
- 琴弦的分布几乎是一致的(不要在意小的偏差,只要它们很小)
- 它为每个参数集输出超过几十亿个string。 如果你的PRNG只产生20亿(31比特的熵)不同的值,产生一个8字符的string(〜47比特的熵)是毫无意义的。
- 这是安全的,因为我希望人们使用这个密码或其他安全令牌。
第一个属性是通过以字母大小为模的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]; new RNGCryptoServiceProvider().GetBytes(bytes); var result = new char[length]; 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); }
你可以得到更好的性能,如果你硬编码字符数组,并依靠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 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); }
结果
在LinqPadtesting。 对于10的string大小,生成:
- 来自Linq = chdgmevhcy [10]
- 从Loop = 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 ms)
- ForLoopNonOptimized(10000x)= 33336滴答已过(3.3336毫秒)
- 重复(10000x)= 78547滴答(7.8547毫秒)
- GenerateRandomString(10000x)= 27416滴答已过(2.7416毫秒)
- SecureFastRandom(10000x)= 13176滴答(5ms)最低[不同的机器]
- SecureFastRandom-NoCache(10000x)= 39541滴答已过(17毫秒)最低[不同的机器]
一行代码Membership.GeneratePassword()诀窍:)
这是一个相同的演示 。
如果你只需要一个伪随机字母数字代码,这是用户友好的,并从一个整数值派生,我提供了一个解决scheme在这里:
生成伪随机字母数字值
它的优点是每个生成的密钥都是唯一的。
另一个select可能是使用Linq并将随机字符聚合到一个string构build器中。
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());
我们也使用自定义string随机,但我们实现是作为一个string的帮手,所以它提供了一些灵活性…
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);
Eric J.编写的代码是相当sl(的(很明显,这是从6年前开始的……他今天可能不会写这个代码),甚至还有一些问题。
与其他一些替代scheme不同的是,这一个是密码良好的。
不真实…密码中存在偏见(如注释中所述), 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); } }
可怕的是,我知道,但我只是忍不住自己:
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); } } }
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); } } }
问题:为什么我应该使用Enumerable.Range
而不是input"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; } }
答案:魔法string是坏的。 有没有人注意到在我的string顶部没有“ I
”? 这个原因,我妈妈教我不要使用魔术弦。
nb 1:像许多其他人一样@dtb说,不要使用System.Random
如果你需要encryption安全性…
NB 2:这个答案不是最有效或最短的,但我想要空间来分开答案和问题。 我的回答的目的是更多地提醒魔法string,而不是提供一个奇特的创新答案。
我正在寻找一个更具体的答案,我想控制随机string的格式,并遇到这个职位。 例如:(汽车)牌照有一个特定的格式(每个国家),我想创build随机牌照。
我决定写这个我自己的Random的扩展方法。 (这是为了重复使用相同的Random对象,因为在multithreading场景中可以使用双倍对象)。 我创build了一个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)]; } }
DTB的解决scheme稍微干净些。
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var random = new Random(); var list = Enumerable.Repeat(0, 8).Select(x=>chars[random.Next(chars.Length)]); return string.Join("", list);
您的风格偏好可能有所不同
尝试结合两个部分:唯一(序列,计数器或date)和随机
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 || // AZ code > 97 && code < 122 // az ) { 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; } }
testing:
[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()) }
不使用Random
的解决scheme:
var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8); var randomStr = new string(chars.SelectMany(str => str) .OrderBy(c => Guid.NewGuid()) .Take(8).ToArray());
我简单的一行代码适用于我:)
string random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o)); Response.Write(random.ToUpper()); Response.Write(random.ToLower());
下面是一个Eric J的解决scheme的变体,即WinRT(Windowsapp store应用)的encryption声音:
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(); }
If performance matters (especially when length is high):
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(); }
After reviewing the other answers and considering CodeInChaos' comments, along with CodeInChaos still biased (although less) answer, I thought a final ultimate cut and paste solution was needed. So while updating my answer I decided to go all out.
For an up to date version of this code, please visit the new Hg repository on Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . I recommend you copy and paste the code from: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default (make sure you click the Raw button to make it easier to copy and make sure you have the latest version, I think this link goes to a specific version of the code, not the latest).
Updated notes:
- Relating to some other answers – If you know the length of the output, you don't need a StringBuilder, and when using ToCharArray, this creates and fills the array (you don't need to create an empty array first)
- Relating to some other answers – You should use NextBytes, rather than getting one at a time for performance
- Technically you could pin the byte array for faster access.. it's usually worth it when your iterating more than 6-8 times over a byte array. (Not done here)
- Use of RNGCryptoServiceProvider for best randomness
- Use of caching of a 1MB buffer of random data – benchmarking shows cached single bytes access speed is ~1000x faster – taking 9ms over 1MB vs 989ms for uncached.
- Optimised rejection of bias zone within my new class.
End solution to question:
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); }
But you need my new (untested) class:
/// <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 } } }
For history – my older solution for this answer, used Random object:
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); }
性能:
- SecureFastRandom – First single run = ~9-33ms . Imperceptible. Ongoing : 5ms (sometimes it goes up to 13ms) over 10,000 iterations, With a single average iteration= 1.5 microseconds. 。 Note: Requires generally 2, but occasionally up to 8 cache refreshes – depends on how many single bytes exceed the bias zone
- Random – First single run = ~0-1ms . Imperceptible. Ongoing : 5ms over 10,000 iterations. With a single average iteration= .5 microseconds. 。 About the same speed.
I know this one is not the best way. But you can try this.
string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters str = str.Replace(".",""); Console.WriteLine("Random string: " + str);
Now in one-liner flavour.
private string RandomName { get { return new string( Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13) .Select(s => { var cryptoResult = new byte[4]; new RNGCryptoServiceProvider().GetBytes(cryptoResult); return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)]; }) .ToArray()); } }
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()); }
I don't know how cryptographically sound this is, but it's more readable and concise than the more intricate solutions by far (imo), and it should be more "random" than System.Random
-based solutions.
return alphabet .OrderBy(c => Guid.NewGuid()) .Take(strLength) .Aggregate( new StringBuilder(), (builder, c) => builder.Append(c)) .ToString();
I can't decide if I think this version or the next one is "prettier", but they give the exact same results:
return new string(alphabet .OrderBy(o => Guid.NewGuid()) .Take(strLength) .ToArray());
Granted, it isn't optimized for speed, so if it's mission critical to generate millions of random strings every second, try another one!
NOTE: This solution doesn't allow for repetitions of symbols in the alphabet, and the alphabet MUST be of equal or greater size than the output string, making this approach less desirable in some circumstances, it all depends on your use-case.
If your values are not completely random, but in fact may depend on something – you may compute an md5 or sha1 hash of that 'somwthing' and then truncate it to whatever length you want.
Also you may generate and truncate a guid.
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; } }
Here is a mechanism to generate a random alpha-numeric string (I use this to generate passwords and test data) without defining the alphabet and numbers,
CleanupBase64 will remove necessary parts in the string and keep adding random alpha-numeric letters recursively.
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); }
Very simple solution. It uses ASCII values and just generates "random" characters in between them.
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(); } }