How can I generate random alphanumeric strings?
如何在C_中生成随机的8个字母数字字符串?
我听说Linq是新的黑色,下面是我使用Linq的尝试:
1 2 3 4 5 6 7 |
(注意:使用
1 2 3 4 5 6 7 8 9 10 |
没有Linq解决方案那么优雅。
(注意:使用
这个实现(通过谷歌找到)在我看来是合理的。
与所提出的一些备选方案不同,这一方案是加密的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | using System.Security.Cryptography; using System.Text; namespace UniqueKey { public class KeyGenerator { public static string GetUniqueKey(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(); } } } |
从这里的备选方案讨论中选出这个
解决方案1-最大"范围"和最灵活的长度
1 2 3 4 5 6 7 8 9 |
这个解决方案比使用guid有更多的范围,因为guid有两个固定位,它们总是相同的,因此不是随机的,例如十六进制的13个字符总是"4"-至少在版本6 guid中是这样。
此解决方案还允许您生成任意长度的字符串。
解决方案2-一行代码-最多可容纳22个字符
1 | Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8); |
只要解决方案1和字符串的范围不同(由于guid中的固定位),就不能生成字符串,但在很多情况下,这会起到作用。
解决方案3-代码略少
1 | Guid.NewGuid().ToString("n").Substring(0, 8); |
主要是为了历史目的把它保存在这里。它使用的代码稍微少一点,但这是因为它使用十六进制而不是base64,因此与其他解决方案相比,它需要更多的字符来表示相同的范围。
这意味着碰撞的可能性更大——用100000次8个字符串的迭代测试它会生成一个副本。
下面是我从SamAllen的例子中偷的一个例子。
如果您只需要8个字符,那么在system.io命名空间中使用path.getrandomFileName()。山姆说,在这里使用"path.getrandomFileName方法有时更优越,因为它使用rngcryptoServiceProvider来实现更好的随机性。但是,它仅限于11个随机字符。"
GetRandomFileName始终返回一个12个字符的字符串,句点为第9个字符。所以您需要去掉句点(因为这不是随机的),然后从字符串中提取8个字符。实际上,您可以只取前8个字符,而不必担心句号。
1 2 3 4 5 6 | public string Get8CharacterRandomString() { string path = Path.GetRandomFileName(); path = path.Replace(".",""); // Remove period. return path.Substring(0, 8); // Return 8 character string } |
谢谢山姆
我的代码的主要目标是:
第一个属性是通过对字母大小取64位值模来实现的。对于小字母(如问题中的62个字符),这会导致可忽略的偏差。第二和第三个属性是通过使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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); } |
最简单的:
1 2 3 4 | public static string GetRandomAlphaNumeric() { return Path.GetRandomFileName().Replace(".","").Substring(0, 8); } |
如果硬编码char数组并依赖
1 2 3 4 5 | public static string GetRandomAlphaNumeric() { var chars ="abcdefghijklmnopqrstuvwxyz0123456789"; return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray()); } |
如果你担心英文字母会在某个时候改变,你可能会失去生意,那么你可以避免硬编码,但应该表现得稍差(与
1 2 3 4 5 6 7 8 9 10 11 12 | 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); } |
最后两种方法如果能使它们成为
只需对本主题中的各种答案进行一些性能比较:
方法和设置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | // 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 SecureFastRandom = VzougLYHYP [10]
- from SecureFastRandom-NoCache = oVQXNGmO1S [10]
性能数字往往略有不同,很偶然,
- LinqIsTheNewBlack (10000x) = 96762 ticks elapsed (9.6762 ms)
- ForLoop (10000x) = 28970 ticks elapsed (2.897 ms)
- ForLoopNonOptimized (10000x) = 33336 ticks elapsed (3.3336 ms)
- Repeat (10000x) = 78547 ticks elapsed (7.8547 ms)
- GenerateRandomString (10000x) = 27416 ticks elapsed (2.7416 ms)
- SecureFastRandom (10000x) = 13176 ticks elapsed (5ms) lowest [Different machine]
- SecureFastRandom-NoCache (10000x) = 39541 ticks elapsed (17ms) lowest [Different machine]
有一行代码
这是一个相同的演示。
EricJ.编写的代码相当草率(很明显这是6年前的代码)。他今天可能不会写这些代码),甚至还有一些问题。
Unlike some of the alternatives presented, this one is cryptographically sound.
不真实…密码中有一个偏差(如注释中所写),
这样可以解决所有问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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); } } |
另一种选择是使用LINQ并将随机字符聚合到StringBuilder中。
1 2 3 4 5 6 | 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 3 4 5 6 7 8 9 10 |
用法
1 | var random ="ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random(); |
或
1 | var random ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16); |
我的简单的一行代码适用于我:)
1 2 3 4 | string random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o)); Response.Write(random.ToUpper()); Response.Write(random.ToLower()); |
在此基础上展开任意长度的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); } |
问:为什么我要浪费时间使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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; } } |
答案:魔法弦是坏的。有没有人注意到我的绳子上面没有"EDOCX1"(9)?因为这个原因,我妈妈教我不要使用魔法弦…
注意1:正如其他许多人如@dtb所说,如果你需要密码安全,不要使用
注意2:这个答案不是最有效的,也不是最短的,但我希望有足够的空间把答案和问题分开。我的答案的目的更多的是警告魔术弦,而不是提供一个奇特的创新答案。
DTB解决方案的稍清洁版本。
1 2 3 4 | var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var random = new Random(); var list = Enumerable.Repeat(0, 8).Select(x=>chars[random.Next(chars.Length)]); return string.Join("", list); |
您的风格偏好可能会有所不同。
1 2 3 4 5 6 |
很可怕,我知道,但我就是忍不住:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <wyn> 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); } } } </wyn> |
在回顾了其他答案并考虑了codeinchaos的评论后,以及codeinchaos仍然偏向(尽管较少)的答案,我认为需要最终的剪切粘贴解决方案。所以在更新我的答案时,我决定全力以赴。
有关此代码的最新版本,请访问BitBucket上的新hg存储库:https://bitback.org/merarischroeder/secureswiftrandom。我建议您从以下位置复制和粘贴代码:https://bitback.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b213379ecdf0ffc7496ea/code/alivate.solidswiftrandom/solidswiftrandom.cs?at=default&fileviewer=file view default(请确保单击"原始"按钮以使复制更容易,并确保您有最新版本,我认为此链接指向代码的特定版本,而不是最新版本)。
更新说明:
问题的最终解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); } |
但你需要我的新(未经测试)课程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | /// <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 } } } |
对于历史-我以前的答案,使用随机对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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); } |
性能:
还检查:
- https://bitback.org/merarischroeder/number-range-with-no-bias/src
- https://stackoverflow.com/a/45118325/887092
这些链接是另一种方法。缓冲可以添加到这个新的代码库中,但最重要的是探索不同的方法来消除偏差,并对速度和优缺点进行基准测试。
我在寻找一个更具体的答案,在这里我想控制随机字符串的格式,并遇到了这篇文章。例如:车牌(汽车)有特定的格式(每个国家),我想创建随机的车牌。我决定为此编写自己的随机扩展方法。(这是为了重用同一个随机对象,因为在多线程场景中可以使用双精度对象)。我创建了一个gist(https://gist.github.com/samvanhoutte/808845ca78b9c041e928),但也将在这里复制扩展类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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)]; } } |
尝试将两部分结合起来:唯一(序列、计数器或日期)和随机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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 || // A-Z code > 97 && code < 122 // a-z ) { 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; } } |
测验:
1 2 3 4 5 6 7 8 9 10 11 | [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()) } |
以下是Eric J解决方案的变体,即针对WinRT(Windows应用商店应用程序)的密码声音:
1 2 3 4 5 6 7 8 9 10 | 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(); } |
如果性能很重要(尤其是长度很长时):
1 2 3 4 5 6 7 8 9 10 11 | 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(); } |
不使用
1 2 3 4 5 | var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8); var randomStr = new string(chars.SelectMany(str => str) .OrderBy(c => Guid.NewGuid()) .Take(8).ToArray()); |
现在在一个线性风味。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | private string RandomName { get { 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()); } } |
我知道这不是最好的办法。但你可以试试这个。
1 2 3 | string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters str = str.Replace(".",""); Console.WriteLine("Random string:" + str); |
我不知道这在密码学上听起来怎么样,但它比迄今为止更复杂的解决方案(IMO)更可读、更简洁,而且它应该比基于
1 2 3 4 5 6 7 | return alphabet .OrderBy(c => Guid.NewGuid()) .Take(strLength) .Aggregate( new StringBuilder(), (builder, c) => builder.Append(c)) .ToString(); |
我不能决定这个版本还是下一个版本更"漂亮",但它们给出的结果完全相同:
1 2 3 4 |
当然,它并没有针对速度进行优化,所以如果每秒生成数百万个随机字符串是任务关键,请尝试另一个!
注意:这个解决方案不允许重复字母表中的符号,而且字母表的大小必须等于或大于输出字符串,这使得这种方法在某些情况下不太可取,这完全取决于您的用例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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; } } |
这里有一种生成随机字母数字字符串的机制(我使用它来生成密码和测试数据),而不定义字母和数字,
cleanupbase64将删除字符串中的必要部分,并继续递归地添加随机字母和数字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); } |
如果您的值不是完全随机的,但事实上可能取决于某个东西——您可以计算该"somwthing"的md5或sha1散列,然后将其截断为所需的长度。
也可以生成和截断一个guid。
非常简单的解决方案。它使用ASCII值,只在它们之间生成"随机"字符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
您只需使用组件
1 2 |
主要用于验证码的实现。但在你的情况下,它也起作用。希望它有帮助。