Generate random alphanumeric string with condition in C #

According to the following code, I need to generate a string in different cases based on the method input. My problem is where I want to create 9A9A (at least 1 number and 1 letter) or 9A9A9A (at least 2 numbers and 2 letters). In most cases, these conditions are 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;
    }

      

+3


source to share


5 answers


Guid

the representation consists of hexadecimal digits, that is, the characters 0

- 9

and a

- f

. The problem with doing this to get a mixture of letters and numbers is that a character at any given position can be either a letter or a decimal digit, with a probability that slopes about 5: 3 in favor of a decimal digit.



If you want to create a specific combination of numbers and letters, you must generate the string one character at a time, without relying on the representation Guid

.

+4


source


I thought I was going - it gives me a good chance to scoff. This is not the most efficient way to generate codes, but it should be pretty 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, because of the funky monkey state machine that implements iterator methods, this code does indeed recycle RNG despite while (true)

.

I've simplified the method a bit GetAuthCode

, but I think it demonstrates a suitable way to generate codes.

+2


source


public class TokenCreator
{
 private Random random = new Random();
 private const string[] chars= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 public static string CreateToken(int length)
 {
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
 }
}

AuthCode = TokenCreator.CreateToken(5);

      

This implementation might help you a little. But again, this does not guarantee that you will get an alphanumeric combination. Sometimes you can only get alphabets and sometimes you can only get numbers. Although the chances are so small.

-2


source


For testing purposes, when I need to generate random strings with specific properties, I use something similar to this. You may need to adapt it to your needs.

public sealed class StringGenerator
{
  private static readonly char[] NumericChars = "0123456789".ToCharArray();
  private static readonly char[] LowerAlphaChars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
  private static readonly char[] UpperAlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();

  public StringGenerator(IRandom rnd)
  {
    Rnd = rnd ?? new SecureRandom();
  }

  private IRandom Rnd
  {
    get;
    set;
  }

  public string Generate(int length, int minNumeric = 0, int minAlpha = 0, AlphaCase alphaCase = AlphaCase.Both)
  {
    if (length < 0)
    {
      throw new ArgumentOutOfRangeException("length");
    }
    if (minNumeric < 0)
    {
      throw new ArgumentOutOfRangeException("minNumeric");
    }
    if (minAlpha < 0)
    {
      throw new ArgumentOutOfRangeException("minAlpha");
    }
    if (length < minNumeric + minAlpha)
    {
      throw new ArgumentException();
    }

    if (length == 0)
    {
      return string.Empty;
    }

    var result = new char[length];

    var index = 0;

    foreach(var numeric in GenerateNumeric().Take(minNumeric))
    {
      result[index++] = numeric;
    }

    var alphaCharacters = GetAlphaCharacters(alphaCase);
    foreach (var alpha in Generate(alphaCharacters).Take(minAlpha))
    {
      result[index++] = alpha;
    }


    var restLength = length - index;

    if (restLength > 0)
    {
      var restCharacters = new List<char>(NumericChars.Concat(alphaCharacters));

      foreach (var rest in Generate(restCharacters).Take(restLength))
      {
        result[index++] = rest;
      }
    }

    // shuffle result
    return new string(result.OrderBy(x => Rnd.Next()).ToArray());
  }

  private IList<char> GetAlphaCharacters(AlphaCase alphaCase)
  {
    switch (alphaCase)
    {
      case AlphaCase.Lower:
        return LowerAlphaChars;

      case AlphaCase.Upper:
        return UpperAlphaChars;

      case AlphaCase.Both:
      default:
        return new List<char>(LowerAlphaChars.Concat(UpperAlphaChars));
    }
  }

  public IEnumerable<char> GenerateNumeric()
  {
    return Generate(NumericChars);
  }
  public IEnumerable<char> GenerateLowerAlpha()
  {
    return Generate(LowerAlphaChars);
  }
  public IEnumerable<char> GenerateUpperAlpha()
  {
    return Generate(UpperAlphaChars);
  }

  public IEnumerable<char> Generate(IList<char> characters)
  {
    if (characters == null)
    {
      throw new ArgumentNullException();
    }
    if (!characters.Any())
    {
      yield break;
    }

    while (true)
    {
      yield return characters[Rnd.Next(characters.Count)];
    }
  }
}

public enum AlphaCase
{
  Lower,
  Upper,
  Both
}

public interface IRandom
{
    int Next();
    int Next(int maxValue);
}

public sealed class SecureRandom : IRandom
{
    private readonly RandomNumberGenerator Rng = new RNGCryptoServiceProvider();

    public int Next()
    {
        var data = new byte[sizeof(int)];
        Rng.GetBytes(data);
        return BitConverter.ToInt32(data, 0) & (int.MaxValue - 1);
    }

    public int Next(int maxValue)
    {
        return Next(0, maxValue);
    }

    public int Next(int minValue, int maxValue)
    {
        if (minValue > maxValue)
        {
            throw new ArgumentOutOfRangeException();
        }
        return (int)Math.Floor(minValue + ((double)maxValue - minValue) * NextDouble());
    }

    public double NextDouble()
    {
        var data = new byte[sizeof(uint)];
        Rng.GetBytes(data);
        var randomUint = BitConverter.ToUInt32(data, 0);
        return randomUint / (uint.MaxValue + 1d);
    }
}

      


Edit: This is an answer to the question of how to generate random alphanumeric strings with conditions. As stated for testing purposes. Do not use as in a context where safety is important.


Edit 2: Shamelessly borrowing from this answer , the solution now uses a wrapper around RNGCryptoServiceProvider . Still not sure if this should be used in a security context, but at least for now it should be "better" than just usingRandom

-2


source


OverView The following code uses Regex.Replace

along IsMatch

to create any length pattern, such as XXXXXX

or XX-XX

, that replaces any X

with a random character or letter.

For example, it XX-XX

can return A(-1d

or with a dash only XXXX

before A(1d

.

Security It uses Web.Security.Membership.GeneratePassword

to get a string of 48 random characters, numbers and what not. A clear password is then extracted from these random characters based on the required pattern.

(at least 1 number and 1 letter)

This is done in a validation regex, which ensures there is at least one alphabetic character and one number. This generate method is called until this check reports a valid match against the rules you specified.

Secure Transport Finally, you need to restore the secure string.

This is triggered when receiving

// This pattern enforces our rule that a pwd must have one letter and one digit.
string pattern = @" # This regex pattern enforces the rules before returning matching
(?=.*[a - zA - Z])  # Somewhere there is a an alphabectic character
(?=.*\d)            # Somewhere there is a number; if no number found return no match.
(.+)                # Successful match, rules are satisfied. Return match";

Random rn = new Random(); // Used to cherry pick from chars to use.

// Creates 48 alpha and non alpha (at least 10 non digit alphas) random characters.
string charsToUse = System.Web.Security.Membership.GeneratePassword(48, 5);

// When replacement is done, replace an `X` matched with a random char. 
MatchEvaluator RandomChar = delegate (Match m)
{
    return charsToUse[rn.Next(charsToUse.Length)].ToString();
};

Func<string, string> Validate = 
      (string str) => Regex.IsMatch(str, pattern, RegexOptions.IgnorePatternWhitespace) 
                      ? str : string.Empty; // return empty on failure.

string pwdClear = string.Empty;

// Generate valid pwd based on rules. Loop until rules are met.
while (string.IsNullOrEmpty(pwdClear))
    pwdClear = Validate(Regex.Replace("XXXX-XXXX-XXXX-XXXX-XXXX", "X", RandomChar));

// Create a secure string for the password for transportation.
SecureString ss = new SecureString();

pwdClear.ToList()
        .ForEach(chr => ss.AppendChar(chr));

      


This answer is based on an unsafe implementation on my blog, see C #: Generate a random sequence of numbers and letters from a custom template and Symbols

-2


source







All Articles