【发布时间】:2019-05-14 10:57:41
【问题描述】:
我正在尝试使用C# 生成随机 Base36 字符串。我使用的是RandomNumberGenerator 而不是Random,因为代码需要是线程安全的。我有以下代码设置:
private readonly RandomNumberGenerator _random = RandomNumberGenerator.Create();
private string GenerateBase36Token(int length)
{
string token = string.Empty;
for (int i = 0; i < length; i++)
{
byte[] bytes = new byte[100];
_random.GetBytes(bytes);
token += ToBase36String(bytes)[0];
}
return token;
}
private string ToBase36String(byte[] toConvert)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
BigInteger dividend = new BigInteger(toConvert);
StringBuilder builder = new StringBuilder();
while (dividend != 0)
{
BigInteger remainder;
dividend = BigInteger.DivRem(dividend, alphabet.Length, out remainder);
builder.Insert(0, alphabet[Math.Abs((int)remainder)]);
}
return builder.ToString();
}
这似乎有效,但是从结果来看,字符串显然没有均匀地分布潜在的字符。有很多重复的字母和数字很少出现。
问题是只取随机字符串的第一个字符还是字符串的构建方式有问题?
【问题讨论】:
-
这里是我得到的分布:0,5163,5062,5148,53.138,143,11.154,137,143,1146,148,147,147,146,148,147,1160,148,14.147,114.145,142,141,139,145,14.14,147,1475,164,155,161,147,145,157,我从未得到过字母的“A”。事实证明,while 循环是问题的一部分。只做一次 DivRem 比做它直到你达到零要好。我的概率老师一直在问这个问题:“如果你有一副完全随机的牌,然后再洗牌一次。你得到的牌或多或少是随机的”?这是一个随机播放(while 循环)给出的随机性要小得多的情况。