0

I would like to create a function that allows me to generate a random string with certain conditions like maximum 2 digits, etc.

So far I've found this but I don't know how to make it two digits maximum:

public static string Generate(int size)
        {
            const string chars = "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            var random = new Random();
            return new string(Enumerable.Repeat(chars, size).Select(s => s[random.Next(s.Length)]).ToArray());
        }
Peter O.
  • 32,158
  • 14
  • 82
  • 96
Fanfarone
  • 131
  • 1
  • 7
  • Change the size to hard coded 2 – Jawad Dec 13 '19 at 15:43
  • 2
    It seems that everyone is missing the word "digits" in the question. OP wants to ensure 2 digits are returned. `size` seems to be about the entire size of the string, not the number of digits. – itsme86 Dec 13 '19 at 15:51
  • You'll need to write some code to do that. For example, have two possible input arrays (your `chars` string), one with digits, and one without. As you are generating the string, if you get past two digits, switch to the non-digits one. That will reduce the entropy of the resulting string though – Flydog57 Dec 13 '19 at 15:53
  • _"certain conditions like"_ - you better list all your conditions, and show what you have tried. If this is about digits, then change `Enumerable.Repeat` to a loop that appends characters to a string as long as that'll fulfill your criteria. You could create criteria as parameters like `int? maxDigits = null, int? maxLowerCase = null, int? maxUppercase = null` and start by validating those parameters. – CodeCaster Dec 13 '19 at 15:56
  • Does this answer your question? [How can I generate random alphanumeric strings?](https://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings) – Peter O. Dec 13 '19 at 19:24

3 Answers3

3

You could hardcode the categories "digit", "lowerCase" and "upperCase" and keep track of how many of each you've already added to the generated string:

public static string Generate(int size, int? maxDigits = null, int? maxLowerCase = null, int? maxUpperCase= null)
{
    if (maxDigits.HasValue && maxLowerCase.HasValue && maxUpperCase.HasValue && maxDigits + maxLowerCase + maxUpperCase< size)
    {
        throw new ArgumentOutOfRangeException($"Can't generate a string of length {size} with the given limits");
    }

    const string chars = "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    var passwordBuilder = new StringBuilder();

    var random = new Random();

    int digitCount = 0, lowerCaseCount = 0, upperCaseCount = 0;

    while (passwordBuilder.Length < size)
    {
        var nextCharacter = chars[random.Next(chars.Length)];

        if (char.IsDigit(nextCharacter) && (!maxDigits.HasValue || digitCount < maxDigits))
        {
            passwordBuilder.Append(nextCharacter);
            digitCount++;
        }
        if (char.IsLower(nextCharacter) && (!maxLowerCase.HasValue || lowerCaseCount < maxLowerCase))
        {
            passwordBuilder.Append(nextCharacter);
            lowerCaseCount++;
        }
        if (char.IsUpper(nextCharacter) && (!maxUpperCase.HasValue || upperCaseCount < maxUpperCase))
        {
            passwordBuilder.Append(nextCharacter);
            upperCaseCount++;
        }
    }

    return passwordBuilder.ToString();
}

Use like:

var password = Generate(10, maxDigits: 2);
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

How about something like this? Once you hit the max number of digits, it changes the source "characters" string.

private static string GenerateRandomString(int size, int maxDigits = 2)
{
    char[] fullChars = "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
    char[] alphaOnly = "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
    char[] current = fullChars;

    var random = new Random();
    var buffer = new StringBuilder(size);
    var digitCount = 0;
    for (var i = 0; i < size; ++i)
    {
        var nextChar = current[random.Next(current.Length)];
        buffer.Append(nextChar);
        if (char.IsDigit(nextChar))
        {
            ++digitCount;
        }

        if (digitCount >= maxDigits)
        {
            current = alphaOnly;
        }
    }

    return buffer.ToString();
}

I tested it using code like:

 for (var i = 0; i < 30; ++i)
 {
     var result = GenerateRandomString(50, 3);
     var digitCount = result.ToCharArray().Where(char.IsDigit).Count();
     Debug.Assert(digitCount <= 3);
 }
Flydog57
  • 6,851
  • 2
  • 17
  • 18
-1

Keep track of the number of digits, and if there are already two, select from a string of non-digit chars:

    string GetRandomString(int length)
    {
        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        var nonDigitChars = chars.Where(x => !char.IsDigit(x)).ToArray();

        var random = new Random();
        int numberOfDigits = 0;

        var randomChars = new char[length];
        for (int i = 0; i < randomChars.Length; i++)
        {
            char c;
            if (numberOfDigits == 2)
            {
                //select from nonDigitChars
                c = nonDigitChars[random.Next(nonDigitChars.Length)];
            }
            else
            {
                c = chars[random.Next(chars.Length)];

                if (char.IsDigit(c))
                {
                    numberOfDigits++;
                }
            }

            randomChars[i] = c;
        }

        return new string(randomChars);
    }
jasonmchoe
  • 491
  • 2
  • 6