Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate random alphanumeric string with condition in C#

Tags:

c#

.net

regex

According to following code , I need to generate a string in different cases based on the method input. My issue is where I wanna generate 9A9A (at least 1 number and 1 letter) or 9A9A9A (at least 2 numbers and 2 letters). In most cases, this conditions is not met.

private AuthMessage GetAuthCode(string CodeType) //(out string Message)
    {
        Guid Guid = Guid.NewGuid();
        Random Random = new Random();
        string AuthCode = string.Empty;
        string RefCode = string.Empty;

        RefCode = Guid.ToString("N");

        switch (CodeType)
        {
            case "0": //9999
                {
                    AuthCode = Random.Next(1000, 9999).ToString();
                    break;
                }
            case "1": //99999
                {
                    AuthCode = Random.Next(10000, 99999).ToString();
                    break;
                }
            case "2": //999999
                {
                    AuthCode = Random.Next(100000, 999999).ToString();
                    break;
                }
            case "3": //999-999
                {
                    AuthCode = Regex.Replace(Random.Next(100000, 999999).ToString(), @"^(.{3})(.{3})$", "$1-$2");
                    break;
                }
            case "4": //9A9A
                {
                    AuthCode = Guid.ToString("N").Substring(14, 4).ToUpper();
                    break;
                }
            case "5": //9A9A9
                {
                    AuthCode = Guid.ToString("N").Substring(15, 5).ToUpper();
                    break;
                }
            case "6": //9A9A9A
                {
                    AuthCode = Guid.ToString("N").Substring(6, 6).ToUpper();
                    break;
                }
            case "7": //9A9-A9A
                {
                    AuthCode = Regex.Replace(Guid.ToString("N").Substring(6, 6), @"(.{3})(.{3})", @"$1-$2").ToUpper();
                    break;
                }
            case "8": //9A9-A9A
                {
                    AuthCode = Regex.Replace(Regex.Replace(Convert.ToBase64String(Guid.ToByteArray()), "[/+=]", "").Substring(0, 6), @"(.{3})(.{3})", @"$1-$2").ToUpper();
                    break;
                }
            default:
                {
                    AuthCode = Random.Next(1000, 9999).ToString();
                    break;
                }
        }

        AuthMessage Response = new AuthMessage();
        Response.AuthCode = AuthCode;
        Response.RefCode = RefCode;

     return Response;
    }
like image 765
Amir Hussein Khaniki Avatar asked May 28 '26 04:05

Amir Hussein Khaniki


2 Answers

Guid representation is composed of hexadecimal digits, i.e. characters 0-9 and a-f. The problem with relying on it to obtain a mixture of letters and numbers is that a character at any given position could be either a letter or a decimal digit, with probability tilted roughly 5:3 in favor of a decimal digit.

If you want to generate a specific mix of digits and letters, you should generate the string one character at a time, without relying on Guid representation.

like image 146
Sergey Kalinichenko Avatar answered May 30 '26 17:05

Sergey Kalinichenko


I thought I'd have a go - it gives me a good chance of being ridiculed. This isn't the most efficient way of generating the codes, but it should be fairly random.

private string GetAuthCode(string CodeType)
{
    var patterns = new Dictionary<char, Func<Char>>()
    {
        { '9', () => RandomBytes().Where(x => x >= '0' && x <= '9').First() },
        { 'A', () => RandomBytes().Where(x => x >= 'A' && x <= 'Z').First() },
        { '-', () => '-' },
    };

    return
        String.IsNullOrEmpty(CodeType)
            ? ""
            : patterns[CodeType[0]]().ToString() + GetAuthCode(CodeType.Substring(1));
}

private IEnumerable<char> RandomBytes()
{
    using (var rng = System.Security.Cryptography.RNGCryptoServiceProvider.Create())
    {
        var bytes = new byte[256];
        while (true)
        {
            rng.GetBytes(bytes);
            foreach (var @byte in bytes)
            {
                yield return (char)@byte;
            }
        }
    }
}

Now, due to the funky monkey state machine that implements iterator methods, this code does dispose of the RNG despite the while (true).

I simplified the GetAuthCode method slightly, but I think this demonstrates a suitable way to generate the codes.

like image 45
Enigmativity Avatar answered May 30 '26 17:05

Enigmativity



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!