随机数发生器 – 可变长度

目前我的程序(见下文)生成长度为8-12个字符的随机字符串(由数字组成)。

public static string GenerateNewCode(int CodeLength) { string newCode = String.Empty; int seed = unchecked(DateTime.Now.Ticks.GetHashCode()); Random random = new Random(seed); // keep going until we find a unique code ` do { newCode = random.Next(Convert.ToInt32(Math.Pow(10, CodeLength - 1)), Convert.ToInt32(Math.Pow(10, CodeLength) - 1)).ToString("0000"); } while (!ConsumerCode.isUnique(newCode)); // return return newCode; } 

但是,它们是该方法的问题,当codeLength为10或更大时,它会导致错误,因为10 9大于int32.MaxValue

不知道如何解决这个问题。

你的代码做了同样的事情没有一些怪胎:

 public static string GenerateNewCode(int CodeLength) { Random random = new Random(); StringBuilder output = new StringBuilder(); do { for (int i = 0; i < CodeLength; i++) { output.Append(random.Next(0, 10)); } } while (!ConsumerCode.isUnique(output.ToString())); return output.ToString(); } 

而不是生成从0到10 n -1的数字,然后将其转换为字符串,生成0到9之间的n个数字,将每个数字转换为字符串,并将它们连接在一起。

我注意到这种技术产生了范围内的数字(比如n = 4)0到9999; 您的原始版本产生的数字从1000到9999.如果您想要保留该属性,则可以生成从1到9而不是0到9的第一个数字。

当然,我这样做的方式更随机,然后’n’连接0 – 9值。

请解释你为什么这么认为。 我很着迷于了解为什么人们会相信谎言。

你能不能创建一个Guid.NewGuid()。Tostring()并截断最重要的字符来获得一个长度为N的随机字符串?

可以,但你不应该 。 GUID不保证是随机的,并且GUID的任何比特子集都不保证是唯一的。 从GUID中取出位并期望这些位具有GUID的属性就像将舵从飞机上取下并期望方向舵飞行一样。 从来没有这样做过。

相反,请将工具用于其设计目的。 GUID旨在提供全局唯一标识符,因此无需使用它们。

你没有问的问题,但可能应该:

我的代码还有什么错误或可疑之处?

 int seed = unchecked(DateTime.Now.Ticks.GetHashCode()); 

那个代码到底在做什么? 首先,随机类已经将当前时间用作种子; 这是不必要的。 第二,究竟什么是“未经检查的算术”表达式,其中不包含算术 ? 第三,为什么你会得到哈希码? 你没有平衡哈希表!

 Random random = new Random(seed); 

如果在同一个tick中调用此方法两次,那么种子将是相同的,因此随机数的序列将是相同的,这意味着您可能会等待很长时间,因为每个生成的数字都将是您的碰撞’独特’集。

一种更好的技术是制作一个随机的静态实例,一次播种。 如果您的程序是单线程的,那就没问题了。 如果它是multithreading的,请确保您不从多个线程访问Random; 它不是线程安全的,它的线程安全违规失败模式不好。

  newCode = random.Next(Convert.ToInt32(Math.Pow(10, CodeLength - 1)), Convert.ToInt32(Math.Pow(10, CodeLength) - 

是否真的有必要每次循环计算两次功率,每次都完全相同? 在循环开始之前解决一次。 代码将更短,更清晰,更快捷。

 while (!ConsumerCode.isUnique(newCode)); 

如果集合已满,则会永久循环。 如果集合几乎已满,那么这会循环长时间。 这是一种用于在范围内生成唯一随机数的潜在不良技术。 只有在事先知道可能生成的数字的数量远远大于集合的最大大小时才这样做。

那么你的方法对于这个function会是什么样子?

我倾向于做这样的事情。 首先,我想要无限的数字:

 // Yield an infinite sequence of pseudo-random digits 0-9 // This method is not thread-safe. private static Random random = new Random(); static IEnumerable Digits() { while(true) yield return random.Next(0, 10); } 

现在我可以生成一个唯一的数字字符串:

 // Generates a random code of given length. If it is not // in the set, adds it and returns the code. If it is // already in the set, tries again. static string AddUniqueCode(int length, HashSet set) { while(true) { string code = string.Join(null, Digits().Take(length)); if (set.Add(code)) return code; } } 

我喜欢我的方法。

如果不可预测性对您很重要,您还可以使Digits方法使用加密随机性而不是伪随机性。 伪随机数很容易预测。

生成0到9之间的随机数; 添加’0′; 把它扔成炭; 现在你有一个随机数字。 根据需要重复多个数字。

像这样: char c = (char)(random.Next(10) + '0');

一种方法可以使用Random.NextDouble()返回0..1之间的数字,然后将其缩放到0..26并使用查找表根据索引返回字母字符。 例如:

 char lookup = new char[] { 'a', 'b', 'c' ... 'z' }; // ensure length 26 int index = (int)(random.NextDouble() * 25.0); return lookup[index] 

更有效的方法是使用ascii表将整数转换为所需的字母数字字符。

最好的祝福,

您可以创建两个随机数,其中第一个随机数的长度为6-10,第二个随机数的长度为2.生成两个数后,将它们组合成一个长度为8-12的字符串。

例:

 public static string GenerateNewCode(int CodeLength) { string newCode = String.Empty; int seed = unchecked(DateTime.Now.Ticks.GetHashCode()); Random random = new Random(seed); // keep going until we find a unique code ` do { // The firstPart int will be a random number that has a length of 6, 7, 8, ,9, or 10 digits int firstPart = random.Next(100000,2147483647); // The secondPart int will be a random number that has a length of two digits int secondPart = random.Next(10,99); // Concatenate firstPart and secondPart. This will create a string that has a length of 8, 9, 10, 11, or 12 chars. newCode = firstPart.ToString() + secondPart.ToString(); } while (!ConsumerCode.isUnique(newCode)); // return return newCode; }