随机字符不使用某些字符

时间:2017-11-21 22:50:34

标签: c# random ascii

我正在尝试创建类似于基本随机密码生成器的内容,包括大写,小写和数字 - 但由于某种原因,这

        static void Main(string[] args)
    {
        bool validLength = false; 
        int userDefinedLength = 0;
        Console.WriteLine("How many characters would you like your password to be?");
        do 
        {
            try
            {
                userDefinedLength = int.Parse(Console.ReadLine());
                validLength = true;
                if (userDefinedLength < 3)
                {
                    Console.WriteLine("Please enter something larger than 3.");
                    validLength = false; 
                }
            }
            catch (Exception)
            {
                Console.WriteLine("Please input a valid integer length.");
            }
        } while (validLength == false);
        char[] passwordArray = new char[userDefinedLength]; 
        int asciiValue = 0;
        char asciiChar = ' ';
        bool validPassword = false; 
        Random ranAsciiGroup = new Random();
        Random ascValue = new Random(); 
        do
        {
            for (int i = 0; i < passwordArray.Length; i++) 
            {
                int randomAsc = 0;
                randomAsc = ranAsciiGroup.Next(1, 4);
                //Console.WriteLine(randomAsc);
                if (randomAsc == 1)
                {
                    asciiValue = ascValue.Next(65, 91);
                    //Console.WriteLine(asciiValue);
                }
                else if (randomAsc == 2) 
                {
                    asciiValue = ascValue.Next(97, 123);
                    //Console.WriteLine(asciiValue);
                }
                else if (randomAsc == 3) 
                {
                    asciiValue = ascValue.Next(48, 58);
                    //Console.WriteLine(asciiValue);
                }
                asciiChar = (char)asciiValue; 
                passwordArray[i] = asciiChar; 
                //validPassword = true;
            }


            bool isDigit = false; 
            bool isUpper = false;
            bool isLower = false;

            for (int i = 0; i < passwordArray.Length; i++) 
            {
                if (char.IsDigit(passwordArray[i]))
                {
                    isDigit = true; 
                }

                if (char.IsUpper(passwordArray[i]))
                {
                    isUpper = true; 
                }

                if (char.IsLower(passwordArray[i]))
                {
                    isLower = true; 
                }
            }

            if (isDigit == true && isUpper == true && isLower == true) 
            {
                validPassword = true; 
            }


        } while (validPassword == false); 

        Console.WriteLine("Your password is..."); 
        Console.ForegroundColor = ConsoleColor.DarkGreen;
        foreach (char c in passwordArray)
        {
            Console.Write(c);
        }
        Console.ReadLine();
    }

它产生的密码似乎没有使用任何小于6的数字。它产生的一些字符非常重复 - 例如小写字母往往具有比其他字符更多的字符 - 或者根本不显示的字符。我将在这里留下100个字符的例子。

m9nj88m8GBpF7Hk87E8p9CAE987pEj7pm7j89iHplo7DIpB87B9irlAk9Ik9C8q8i97B9o8l8GDjj88j898Dmk9A69969Ino988I

2 个答案:

答案 0 :(得分:2)

种子RNG

不要忘记播种随机的实例,例如

var random = new System.Random(Environment.TickCount);

此外,一个实例应该足够了。

消除重复

如果您希望确保表示所有字符,您可以使用其他随机选择技术。例如,您可以生成一个非常长的字符串,其中包含您想要的所有字符,随机排序,然后获取第一个 n 字符。这种方法可以完全消除重复的字符并保证最终使用每个字符。例如:

using System;
using System.Linq;

public class Program
{
    static readonly Random _random = new System.Random(Environment.TickCount);
    const string dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklpmnopqrstuvwxyz0123456789!@#$%^&*()_+-=";

    static string GetPassword(int length)
    {
        return new String
            (
                dictionary
                   .OrderBy( a => _random.NextDouble() )
                   .Take(length)
                   .ToArray()
            );
    }

    public static void Main()
    {
        var s = GetPassword(30);
        Console.WriteLine(s);
    }
}

在这个例子中,我们将字符串视为Enumerable<char>(是的,这是允许的)并使用LINQ方法对其进行随机排序并获取第一个 n 字符。然后,我们将结果传递给包含答案的新System.String的构造函数。

示例输出:

运行#1:

!#t(hfTz0rB5cvKy1d$oeVI2mnsCba

运行#2:

y7Y(MB1pWH$wO5XPD0b+%Rkn9a4F!_

运行#3:

tH92lnh*sL+WOaTYR160&xiZpC5@G3

对我来说很随意。

受控重复

上述解决方案当然只允许字典中每个字符的一个实例。但也许你希望它们能够出现不止一次,但不能太多。如果您想要受控制的,有限数量的可能重复,您可以进行一些小改动:

    static string GetPassword(int length, int maxRepeats)
    {
        return new String
            (
                Enumerable.Range(0, maxRepeats)
                   .SelectMany( i => dictionary )
                   .OrderBy( a => _random.NextDouble() )
                   .Take(length)
                   .ToArray()
            );
    }

在此示例中,我们克隆字典maxRepeats次并使用SelectMany连接它们。然后我们随机排序这个巨大的字符串,并将第一个 n 字符作为密码。

Working code on .NET Fiddle

答案 1 :(得分:0)

System.Random类并非设计为强RNG,它被设计为快速RNG。如果您需要高质量的随机数生成器,则需要使用基于System.Security.Cryptography.RandomNumberGenerator类的生成器。

Here is a gist I found使用加密随机生成器作为现有随机类的内部。

运行它with the new generator给了我

  

mm77D5EDjO0OhOOe8kppiY0toc0HWQjpo37b4LFj56LvcQvA4jE83J8BS8xeX6zcEr2Od8A70v2xFKiY0ROY3gN105rZt6PE8F2i

您可以看到的

似乎没有您找到的偏见。