我如何在c#中生成一个随机的8个字符的字母数字字符串?
当前回答
只需一行代码member . generatepassword()就可以做到这一点。
这里有一个相同的演示。
其他回答
在这个线程中只是一些不同答案的性能比较:
方法与设置
// what's available
public static string possibleChars = "abcdefghijklmnopqrstuvwxyz";
// optimized (?) what's available
public static char[] possibleCharsArray = possibleChars.ToCharArray();
// optimized (precalculated) count
public static int possibleCharsAvailable = possibleChars.Length;
// shared randomization thingy
public static Random random = new Random();
// http://stackoverflow.com/a/1344242/1037948
public string LinqIsTheNewBlack(int num) {
return new string(
Enumerable.Repeat(possibleCharsArray, num)
.Select(s => s[random.Next(s.Length)])
.ToArray());
}
// http://stackoverflow.com/a/1344258/1037948
public string ForLoop(int num) {
var result = new char[num];
while(num-- > 0) {
result[num] = possibleCharsArray[random.Next(possibleCharsAvailable)];
}
return new string(result);
}
public string ForLoopNonOptimized(int num) {
var result = new char[num];
while(num-- > 0) {
result[num] = possibleChars[random.Next(possibleChars.Length)];
}
return new string(result);
}
public string Repeat(int num) {
return new string(new char[num].Select(o => possibleCharsArray[random.Next(possibleCharsAvailable)]).ToArray());
}
// http://stackoverflow.com/a/1518495/1037948
public string GenerateRandomString(int num) {
var rBytes = new byte[num];
random.NextBytes(rBytes);
var rName = new char[num];
while(num-- > 0)
rName[num] = possibleCharsArray[rBytes[num] % possibleCharsAvailable];
return new string(rName);
}
//SecureFastRandom - or SolidSwiftRandom
static string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length];
char[] rName = new char[Length];
SolidSwiftRandom.GetNextBytesWithMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(rName);
}
结果
在LinqPad中测试。对于长度为10的字符串,生成:
from Linq = chdgmevhcy [10] from Loop = gtnoaryhxr [10] from Select = rsndbztyby [10] from GenerateRandomString = owyefjjakj [10] from securefastrrandom = VzougLYHYP [10] from securefastrrandom - nocache = oVQXNGmO1S [10]
性能数据会有细微的变化,偶尔NonOptimized会更快,有时ForLoop和GenerateRandomString会切换谁领先。
LinqIsTheNewBlack (10000x) = 96762 ticks elapsed (9.6762 ms) ForLoop (10000x) = 28970滴答流逝(2.897毫秒) ForLoopNonOptimized (10000x) = 33336滴答流逝(3.3336毫秒) 重复(10000x) = 78547滴答流逝(7.8547毫秒) GenerateRandomString (10000x) = 27416 tick elapsed (2.7416 ms) securefastrrandom (10000x) = 13176滴答流逝(5ms)最低[不同的机器] securefastrrandom - nocache (10000x) = 39541 ticks elapsed (17ms) low[不同的机器]
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());
}
更新。net 6。RNGCryptoServiceProvider被标记为obsolete。相反,调用RandomNumberGenerator.Create()。答案中的代码已相应更新。
根据评论更新。原始实现生成a-h的时间为1.95%,其余字符的时间为1.56%。更新生成所有字符~1.61%的时间。 FRAMEWORK支持- . net Core 3(以及未来支持. net Standard 2.1或以上版本的平台)提供了一个加密的方法RandomNumberGenerator.GetInt32(),在期望的范围内生成一个随机整数。
与目前提出的一些替代方案不同,这个方案在密码学上是合理的。
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();
}
}
}
基于这里对替代方案的讨论,并根据下面的评论进行了更新/修改。
下面是一个小型测试工具,演示了旧输出和更新输出中的字符分布。关于随机性分析的深入讨论,请访问random.org。
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")}%");
}
}
}
}
更新7/25/2022
根据评论中的一个问题,我很好奇这种分布是否真的是随机的。
我不是统计学家,但我可以在电视上扮演一个。如果一位真正的统计学家愿意插话,那将是最受欢迎的。
有62个可能的输出值(A-Za-Z0-9)和int。用于选择数组索引的最大值。int。MaxValue % 62是1,所以一个字符被选中的概率是其他字符的十亿分之一。我们可以通过在索引之前随机旋转输出值数组来进一步减少选择偏差。
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();
}
}
Eric J.写的代码很潦草(很明显这是6年前写的……他今天可能不会写那个代码),甚至还有一些问题。
与目前提出的一些替代方案不同,这个方案在密码学上是合理的。
不真实的…在密码中有一个偏差(正如在注释中所写的那样),bcdefgh比其他的更有可能(a不是,因为通过GetNonZeroBytes,它不会生成值为0的字节,因此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);
}
}
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);
您的风格偏好可能会有所不同。
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 为什么Visual Studio 2015/2017/2019测试运行器没有发现我的xUnit v2测试
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 如何在Ruby中生成a和b之间的随机数?
- 自动化invokerrequired代码模式
- 没有ListBox。SelectionMode="None",是否有其他方法禁用列表框中的选择?
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?